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