On Sat, Jan 19, 2019 at 2:18 AM Johannes Doerfert via cfe-commits <
cfe-commits@lists.llvm.org> wrote:

> Author: jdoerfert
> Date: Fri Jan 18 21:36:54 2019
> New Revision: 351629
>
> URL: http://llvm.org/viewvc/llvm-project?rev=351629&view=rev
> Log:
> Emit !callback metadata and introduce the callback attribute
>
>   With commit r351627, LLVM gained the ability to apply (existing) IPO
>   optimizations on indirections through callbacks, or transitive calls.
>   The general idea is that we use an abstraction to hide the middle man
>   and represent the callback call in the context of the initial caller.
>   It is described in more detail in the commit message of the LLVM patch
>   r351627, the llvm::AbstractCallSite class description, and the
>   language reference section on callback-metadata.
>
>   This commit enables clang to emit !callback metadata that is
>   understood by LLVM. It does so in three different cases:
>     1) For known broker functions declarations that are directly
>        generated, e.g., __kmpc_fork_call for the OpenMP pragma parallel.
>     2) For known broker functions that are identified by their name and
>        source location through the builtin detection, e.g.,
>        pthread_create from the POSIX thread API.
>     3) For user annotated functions that carry the "callback(callee, ...)"
>        attribute. The attribute has to include the name, or index, of
>        the callback callee and how the passed arguments can be
>        identified (as many as the callback callee has). See the callback
>        attribute documentation for detailed information.
>
> Differential Revision: https://reviews.llvm.org/D55483
>
> Added:
>     cfe/trunk/test/CodeGen/attr-callback.c
>     cfe/trunk/test/CodeGen/callback_annotated.c
>     cfe/trunk/test/CodeGen/callback_openmp.c
>     cfe/trunk/test/CodeGen/callback_pthread_create.c
>     cfe/trunk/test/CodeGenCXX/attr-callback.cpp
>     cfe/trunk/test/Sema/attr-callback-broken.c
>     cfe/trunk/test/Sema/attr-callback.c
>     cfe/trunk/test/SemaCXX/attr-callback-broken.cpp
>     cfe/trunk/test/SemaCXX/attr-callback.cpp
> Modified:
>     cfe/trunk/include/clang/AST/ASTContext.h
>     cfe/trunk/include/clang/Basic/Attr.td
>     cfe/trunk/include/clang/Basic/AttrDocs.td
>     cfe/trunk/include/clang/Basic/Builtins.def
>     cfe/trunk/include/clang/Basic/Builtins.h
>     cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>     cfe/trunk/lib/AST/ASTContext.cpp
>     cfe/trunk/lib/Basic/Builtins.cpp
>     cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp
>     cfe/trunk/lib/CodeGen/CodeGenModule.cpp
>     cfe/trunk/lib/Parse/ParseDecl.cpp
>     cfe/trunk/lib/Sema/SemaDecl.cpp
>     cfe/trunk/lib/Sema/SemaDeclAttr.cpp
>     cfe/trunk/test/Analysis/retain-release.m
>     cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test
>     cfe/trunk/test/OpenMP/parallel_codegen.cpp
>     cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
>
> Modified: cfe/trunk/include/clang/AST/ASTContext.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/AST/ASTContext.h (original)
> +++ cfe/trunk/include/clang/AST/ASTContext.h Fri Jan 18 21:36:54 2019
> @@ -2003,6 +2003,9 @@ public:
>      /// No error
>      GE_None,
>
> +    /// Missing a type
> +    GE_Missing_type,
> +
>      /// Missing a type from <stdio.h>
>      GE_Missing_stdio,
>
>
> Modified: cfe/trunk/include/clang/Basic/Attr.td
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/Attr.td (original)
> +++ cfe/trunk/include/clang/Basic/Attr.td Fri Jan 18 21:36:54 2019
> @@ -190,6 +190,9 @@ class VariadicIdentifierArgument<string
>  // 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>;
>
> @@ -1210,6 +1213,13 @@ def FormatArg : InheritableAttr {
>    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]>;
>
> Modified: cfe/trunk/include/clang/Basic/AttrDocs.td
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/AttrDocs.td?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/AttrDocs.td (original)
> +++ cfe/trunk/include/clang/Basic/AttrDocs.td Fri Jan 18 21:36:54 2019
> @@ -3781,6 +3781,55 @@ it rather documents the programmer's int
>    }];
>  }
>
> +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 is
> potentially
> +inspected, captured, or modified. Parameter names and indices can be
> mixed in
> +the callback attribute.
> +
> +The ``callback`` attribute, which is 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. In
> addition,
> +the declarations of `__kmpc_fork_teams` and `__kmpc_fork_call`, generated
> for
> +`#pragma omp target teams` and `#pragma omp parallel`, respectively, are
> also
> +automatically recognized as broker functions. Further functions might be
> added
> +in the future.
> +
> +  .. 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 = [{
>
> Modified: cfe/trunk/include/clang/Basic/Builtins.def
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Builtins.def?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/Builtins.def (original)
> +++ cfe/trunk/include/clang/Basic/Builtins.def Fri Jan 18 21:36:54 2019
> @@ -93,6 +93,8 @@
>  //  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 +962,9 @@ LIBBUILTIN(strncasecmp, "icC*cC*z", "f",
>  // 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)
>
> Modified: cfe/trunk/include/clang/Basic/Builtins.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Builtins.h?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/Builtins.h (original)
> +++ cfe/trunk/include/clang/Basic/Builtins.h Fri Jan 18 21:36:54 2019
> @@ -194,6 +194,12 @@ public:
>    /// 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.
>    ///
>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Jan 18
> 21:36:54 2019
> @@ -2578,6 +2578,20 @@ def err_format_attribute_result_not : Er
>  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<
> +  "'callback' attribute specifies no callback callee">;
> +def err_callback_attribute_invalid_callee : Error<
> +  "'callback' attribute specifies invalid callback callee">;
> +def err_callback_attribute_multiple : Error<
> +  "multiple 'callback' attributes specified">;
> +def err_callback_attribute_argument_unknown : Error<
> +  "'callback' attribute argument %0 is not a known function parameter">;
> +def err_callback_callee_no_function_type : Error<
> +  "'callback' attribute callee does not have function type">;
> +def err_callback_callee_is_variadic : Error<
> +  "'callback' attribute callee may not be variadic">;
> +def err_callback_implicit_this_not_available : Error<
> +  "'callback' argument at position %0 references unavailable implicit
> 'this'">;
>  def err_init_method_bad_return_type : Error<
>    "init methods must return an object pointer type, not %0">;
>  def err_attribute_invalid_size : Error<
>
> Modified: cfe/trunk/lib/AST/ASTContext.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/ASTContext.cpp (original)
> +++ cfe/trunk/lib/AST/ASTContext.cpp Fri Jan 18 21:36:54 2019
> @@ -9518,6 +9518,10 @@ QualType ASTContext::GetBuiltinType(unsi
>                                      GetBuiltinTypeError &Error,
>                                      unsigned *IntegerConstantArgs) const {
>    const char *TypeStr = BuiltinInfo.getTypeString(Id);
> +  if (TypeStr[0] == '\0') {
> +    Error = GE_Missing_type;
> +    return {};
> +  }
>
>    SmallVector<QualType, 8> ArgTypes;
>
>
> Modified: cfe/trunk/lib/Basic/Builtins.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Builtins.cpp?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Basic/Builtins.cpp (original)
> +++ cfe/trunk/lib/Basic/Builtins.cpp Fri Jan 18 21:36:54 2019
> @@ -156,6 +156,33 @@ bool Builtin::Context::isScanfLike(unsig
>    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 ||
>
> Modified: cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp Fri Jan 18 21:36:54 2019
> @@ -1677,6 +1677,22 @@ CGOpenMPRuntime::createRuntimeFunction(u
>      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 @@ CGOpenMPRuntime::createRuntimeFunction(u
>      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: {
>
> Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Fri Jan 18 21:36:54 2019
> @@ -1603,6 +1603,23 @@ void CodeGenModule::SetFunctionAttribute
>
>    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) {
>
> Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
> +++ cfe/trunk/lib/Parse/ParseDecl.cpp Fri Jan 18 21:36:54 2019
> @@ -223,6 +223,15 @@ static bool attributeHasVariadicIdentifi
>  #undef CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST
>  }
>
> +/// Determine whether the given attribute treats kw_this as an identifier.
> +static bool attributeTreatsKeywordThisAsIdentifier(const IdentifierInfo
> &II) {
> +#define CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST
> +  return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
> +#include "clang/Parse/AttrParserStringSwitches.inc"
> +           .Default(false);
> +#undef CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST
> +}
> +
>  /// Determine whether the given attribute parses a type argument.
>  static bool attributeIsTypeArgAttr(const IdentifierInfo &II) {
>  #define CLANG_ATTR_TYPE_ARG_LIST
> @@ -287,6 +296,12 @@ unsigned Parser::ParseAttributeArgsCommo
>    // Ignore the left paren location for now.
>    ConsumeParen();
>
> +  bool ChangeKWThisToIdent =
> attributeTreatsKeywordThisAsIdentifier(*AttrName);
> +
> +  // Interpret "kw_this" as an identifier if the attributed requests it.
> +  if (ChangeKWThisToIdent && Tok.is(tok::kw_this))
> +    Tok.setKind(tok::identifier);
> +
>    ArgsVector ArgExprs;
>    if (Tok.is(tok::identifier)) {
>      // If this attribute wants an 'identifier' argument, make it so.
> @@ -314,6 +329,10 @@ unsigned Parser::ParseAttributeArgsCommo
>
>      // Parse the non-empty comma-separated list of expressions.
>      do {
> +      // Interpret "kw_this" as an identifier if the attributed requests
> it.
> +      if (ChangeKWThisToIdent && Tok.is(tok::kw_this))
> +        Tok.setKind(tok::identifier);
> +
>        ExprResult ArgExpr;
>        if (Tok.is(tok::identifier) &&
>            attributeHasVariadicIdentifierArg(*AttrName)) {
>
> Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Jan 18 21:36:54 2019
> @@ -1927,10 +1927,13 @@ static void LookupPredefedObjCSuperType(
>        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 @@ NamedDecl *Sema::LazilyCreateBuiltin(Ide
>    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;
>    }
>
> @@ -13580,6 +13584,13 @@ void Sema::AddKnownFunctionAttributes(Fu
>                                                FD->getLocation()));
>      }
>
> +    // Handle automatically recognized callbacks.
> +    SmallVector<int, 4> Encoding;
> +    if (!FD->hasAttr<CallbackAttr>() &&
> +        Context.BuiltinInfo.performsCallback(BuiltinID, Encoding))
> +      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.
>
> Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Fri Jan 18 21:36:54 2019
> @@ -3480,6 +3480,144 @@ static void handleFormatAttr(Sema &S, De
>      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 I = 0, E = AL.getNumArgs(); I < E; ++I) {
> +    SourceRange SR;
> +    int32_t ArgIdx;
> +
> +    if (AL.isArgIdent(I)) {
> +      IdentifierLoc *IdLoc = AL.getArgAsIdent(I);
> +      auto It = NameIdxMapping.find(IdLoc->Ident->getName());
> +      if (It == UnknownName) {
> +        S.Diag(AL.getLoc(), diag::err_callback_attribute_argument_unknown)
> +            << IdLoc->Ident << IdLoc->Loc;
> +        return;
> +      }
> +
> +      SR = SourceRange(IdLoc->Loc);
> +      ArgIdx = It->second;
> +    } else if (AL.isArgExpr(I)) {
> +      Expr *IdxExpr = AL.getArgAsExpr(I);
> +
> +      // If the expression is not parseable as an int32_t we have a
> problem.
> +      if (!checkUInt32Argument(S, AL, IdxExpr, (uint32_t &)ArgIdx, I + 1,
> +                               false)) {
> +        S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
> +            << AL << (I + 1) << IdxExpr->getSourceRange();
> +        return;
> +      }
> +
> +      // Check oob, excluding the special values, 0 and -1.
> +      if (ArgIdx < -1 || ArgIdx > NumArgs) {
> +        S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
> +            << AL << (I + 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)
> +          << (I + 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_attribute_wrong_number_arguments)
> +        << AL << (unsigned)(EncodingIndices.size() - 1);
> +    return;
> +  }
> +
> +  if (CalleeFnProtoType->getNumParams() < EncodingIndices.size() - 1) {
> +    S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments)
> +        << AL << (unsigned)(EncodingIndices.size() - 1);
> +    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;
> @@ -6451,6 +6589,9 @@ static void ProcessDeclAttribute(Sema &S
>    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;
>
> Modified: cfe/trunk/test/Analysis/retain-release.m
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/retain-release.m?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/Analysis/retain-release.m (original)
> +++ cfe/trunk/test/Analysis/retain-release.m Fri Jan 18 21:36:54 2019
> @@ -2,7 +2,7 @@
>  // 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:     -analyzer-checker=debug.ExprInspection -fblocks
> -verify=expected,C %s\
>  // RUN:     -Wno-objc-root-class -analyzer-output=plist -o %t.objc.plist
>  // RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10\
>  // RUN:     -analyzer-checker=core,osx.coreFoundation.CFRetainRelease\
> @@ -1202,7 +1202,7 @@ typedef __darwin_pthread_attr_t pthread_
>  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);
>
> Added: cfe/trunk/test/CodeGen/attr-callback.c
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/attr-callback.c?rev=351629&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/CodeGen/attr-callback.c (added)
> +++ cfe/trunk/test/CodeGen/attr-callback.c Fri Jan 18 21:36:54 2019
> @@ -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}
>
> Added: cfe/trunk/test/CodeGen/callback_annotated.c
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/callback_annotated.c?rev=351629&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/CodeGen/callback_annotated.c (added)
> +++ cfe/trunk/test/CodeGen/callback_annotated.c Fri Jan 18 21:36:54 2019
> @@ -0,0 +1,73 @@
> +// 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);
> +}
> +
> +void *broker2(void (*callee)(void));
> +
> +// RUN1-DAG: declare !callback ![[cid2:[0-9]+]] i8* @broker2
> +__attribute__((callback(callee))) void *broker2(void (*callee)(void));
> +
> +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}
>
> Added: cfe/trunk/test/CodeGen/callback_openmp.c
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/callback_openmp.c?rev=351629&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/CodeGen/callback_openmp.c (added)
> +++ cfe/trunk/test/CodeGen/callback_openmp.c Fri Jan 18 21:36:54 2019
> @@ -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)
> +}
>
> Added: cfe/trunk/test/CodeGen/callback_pthread_create.c
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/callback_pthread_create.c?rev=351629&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/CodeGen/callback_pthread_create.c (added)
> +++ cfe/trunk/test/CodeGen/callback_pthread_create.c Fri Jan 18 21:36:54
> 2019
> @@ -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>


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.

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.

-Chandler


> +
> +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);
> +}
>
> Added: cfe/trunk/test/CodeGenCXX/attr-callback.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/attr-callback.cpp?rev=351629&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/attr-callback.cpp (added)
> +++ cfe/trunk/test/CodeGenCXX/attr-callback.cpp Fri Jan 18 21:36:54 2019
> @@ -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}
>
> Modified:
> cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test
> (original)
> +++ cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test
> Fri Jan 18 21:36:54 2019
> @@ -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)
>
> Modified: cfe/trunk/test/OpenMP/parallel_codegen.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/parallel_codegen.cpp?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/OpenMP/parallel_codegen.cpp (original)
> +++ cfe/trunk/test/OpenMP/parallel_codegen.cpp Fri Jan 18 21:36:54 2019
> @@ -82,9 +82,9 @@ int main (int argc, char **argv) {
>  // 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 @@ int main (int argc, char **argv) {
>
>  // 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
>
> Added: cfe/trunk/test/Sema/attr-callback-broken.c
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-callback-broken.c?rev=351629&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/Sema/attr-callback-broken.c (added)
> +++ cfe/trunk/test/Sema/attr-callback-broken.c Fri Jan 18 21:36:54 2019
> @@ -0,0 +1,75 @@
> +// RUN: %clang_cc1 %s -verify -fsyntax-only
> +
> +__attribute__((callback())) void no_callee(void (*callback)(void)); //
> expected-error {{'callback' attribute specifies no callback callee}}
> +
> +__attribute__((callback(1, 1))) void too_many_args_1(void
> (*callback)(void)) {}      // expected-error {{'callback' attribute takes
> one argument}}
> +__attribute__((callback(1, -1))) void too_many_args_2(double
> (*callback)(void));     // expected-error {{'callback' attribute takes one
> argument}}
> +__attribute__((callback(1, 2, 2))) void too_many_args_3(void
> (*callback)(int), int); // expected-error {{'callback' attribute requires
> exactly 2 arguments}}
> +
> +__attribute__((callback(1, 2))) void too_few_args_1(void (*callback)(int,
> int), int); // expected-error {{'callback' attribute takes one argument}}
> +__attribute__((callback(1))) void too_few_args_2(int (*callback)(int));
>              // expected-error {{'callback' attribute takes no arguments}}
> +__attribute__((callback(1, -1))) void too_few_args_3(void
> (*callback)(int, int)) {}   // expected-error {{'callback' attribute takes
> one argument}}
> +
> +__attribute__((callback(-1))) void oob_args_1(void (*callback)(void));
>      // expected-error {{'callback' attribute specifies invalid callback
> callee}}
> +__attribute__((callback(2))) void oob_args_2(int *(*callback)(void)) {}
>       // expected-error {{'callback' attribute parameter 1 is out of
> bounds}}
> +__attribute__((callback(1, 3))) void oob_args_3(short (*callback)(int),
> int);  // expected-error {{'callback' attribute parameter 2 is out of
> bounds}}
> +__attribute__((callback(-2, 2))) void oob_args_4(void *(*callback)(int),
> int); // expected-error {{'callback' attribute parameter 1 is out of
> bounds}}
> +__attribute__((callback(1, -2))) void oob_args_5(void *(*callback)(int),
> int); // expected-error {{'callback' attribute parameter 2 is out of
> bounds}}
> +__attribute__((callback(1, 2))) void oob_args_6(void *(*callback)(int),
> ...);  // expected-error {{'callback' attribute parameter 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 {{'callback' attribute specifies invalid callback callee}}
> +#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' attribute callee may not be
> variadic}}
> +__attribute__((callback(1, 1))) void vararg_cb_2(void (*callback)(int,
> ...), int a); // expected-error {{'callback' attribute callee may 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 requires exactly 6 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 requires exactly 6 arguments}}
> +
> +__attribute__((callback(1, -1, 1))) void self_arg_1(void (*callback)(int,
> ...)) {}          // expected-error {{'callback' attribute requires exactly
> 2 arguments}}
> +__attribute__((callback(1, -1, 1, -1, -1, 1))) void self_arg_2(void
> (*callback)(int, ...)); // expected-error {{'callback' attribute requires
> exactly 5 arguments}}
> +
> +__attribute__((callback(cb))) void unknown_name1(void (*callback)(void))
> {}     // expected-error {{'callback' attribute argument 'cb' is not a
> known function parameter}}
> +__attribute__((callback(cb, ab))) void unknown_name2(void (*cb)(int), int
> a) {} // expected-error {{'callback' attribute argument 'ab' is not a known
> function parameter}}
> +
> +__attribute__((callback(callback, 1))) void too_many_args_1b(void
> (*callback)(void)) {}      // expected-error {{'callback' attribute takes
> one argument}}
> +__attribute__((callback(callback, __))) void too_many_args_2b(double
> (*callback)(void));     // expected-error {{'callback' attribute takes one
> argument}}
> +__attribute__((callback(callback, 2, 2))) void too_many_args_3b(void
> (*callback)(int), int); // expected-error {{'callback' attribute requires
> exactly 2 arguments}}
> +
> +__attribute__((callback(callback, a))) void too_few_args_1b(void
> (*callback)(int, int), int a); // expected-error {{'callback' attribute
> takes one argument}}
> +__attribute__((callback(callback))) void too_few_args_2b(int
> (*callback)(int));                 // expected-error {{'callback' attribute
> takes no arguments}}
> +__attribute__((callback(callback, __))) void too_few_args_3b(void
> (*callback)(int, int)) {}     // expected-error {{'callback' attribute
> takes one argument}}
> +
> +__attribute__((callback(__))) void oob_args_1b(void (*callback)(void));
> // expected-error {{'callback' attribute specifies invalid callback callee}}
> +
> +__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 {{'callback' attribute specifies invalid callback callee}}
> +#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' attribute callee
> may not be variadic}}
> +__attribute__((callback(1, a))) void vararg_cb_2b(void (*callback)(int,
> ...), int a);    // expected-error {{'callback' attribute callee may 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 requires exactly 6 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 requires exactly 6 arguments}}
> +
> +__attribute__((callback(1, __, callback))) void self_arg_1b(void
> (*callback)(int, ...)) {}                        // expected-error
> {{'callback' attribute requires exactly 2 arguments}}
> +__attribute__((callback(callback, __, callback, __, __, callback))) void
> self_arg_2b(void (*callback)(int, ...)); // expected-error {{'callback'
> attribute requires exactly 5 arguments}}
>
> Added: cfe/trunk/test/Sema/attr-callback.c
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-callback.c?rev=351629&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/Sema/attr-callback.c (added)
> +++ cfe/trunk/test/Sema/attr-callback.c Fri Jan 18 21:36:54 2019
> @@ -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);
>
> Added: cfe/trunk/test/SemaCXX/attr-callback-broken.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-callback-broken.cpp?rev=351629&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/attr-callback-broken.cpp (added)
> +++ cfe/trunk/test/SemaCXX/attr-callback-broken.cpp Fri Jan 18 21:36:54
> 2019
> @@ -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
> +};
>
> Added: cfe/trunk/test/SemaCXX/attr-callback.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-callback.cpp?rev=351629&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/attr-callback.cpp (added)
> +++ cfe/trunk/test/SemaCXX/attr-callback.cpp Fri Jan 18 21:36:54 2019
> @@ -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)) {}
>
> Modified: cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp (original)
> +++ cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp Fri Jan 18 21:36:54 2019
> @@ -776,6 +776,11 @@ namespace {
>      }
>    };
>
> +  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) {
> @@ -1284,6 +1289,8 @@ createArgument(const Record &Arg, String
>      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")
> @@ -2117,6 +2124,7 @@ static bool isVariadicIdentifierArgument
>           llvm::StringSwitch<bool>(
>               Arg->getSuperClasses().back().first->getName())
>               .Case("VariadicIdentifierArgument", true)
> +             .Case("VariadicParamOrParamIdxArgument", true)
>               .Default(false);
>  }
>
> @@ -2159,6 +2167,34 @@ static void emitClangAttrIdentifierArgLi
>    OS << "#endif // CLANG_ATTR_IDENTIFIER_ARG_LIST\n\n";
>  }
>
> +static bool keywordThisIsaIdentifierInArgument(const Record *Arg) {
> +  return !Arg->getSuperClasses().empty() &&
> +         llvm::StringSwitch<bool>(
> +             Arg->getSuperClasses().back().first->getName())
> +             .Case("VariadicParamOrParamIdxArgument", true)
> +             .Default(false);
> +}
> +
> +static void emitClangAttrThisIsaIdentifierArgList(RecordKeeper &Records,
> +                                                  raw_ostream &OS) {
> +  OS << "#if defined(CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST)\n";
> +  std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
> +  for (const auto *A : Attrs) {
> +    // Determine whether the first argument is a variadic identifier.
> +    std::vector<Record *> Args = A->getValueAsListOfDefs("Args");
> +    if (Args.empty() || !keywordThisIsaIdentifierInArgument(Args[0]))
> +      continue;
> +
> +    // All these spellings take an identifier argument.
> +    forEachUniqueSpelling(*A, [&](const FlattenedSpelling &S) {
> +      OS << ".Case(\"" << S.name() << "\", "
> +         << "true"
> +         << ")\n";
> +    });
> +  }
> +  OS << "#endif // CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST\n\n";
> +}
> +
>  namespace clang {
>
>  // Emits the class definitions for attributes.
> @@ -3767,6 +3803,7 @@ void EmitClangAttrParserStringSwitches(R
>    emitClangAttrArgContextList(Records, OS);
>    emitClangAttrIdentifierArgList(Records, OS);
>    emitClangAttrVariadicIdentifierArgList(Records, OS);
> +  emitClangAttrThisIsaIdentifierArgList(Records, OS);
>    emitClangAttrTypeArgList(Records, OS);
>    emitClangAttrLateParsedList(Records, OS);
>  }
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits@lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to