r196408 - ObjectiveC - Introducing objc_bridge_related attribute

Aaron Ballman aaron at aaronballman.com
Wed Dec 4 12:51:27 PST 2013


On Wed, Dec 4, 2013 at 3:32 PM, Fariborz Jahanian <fjahanian at apple.com> wrote:
> Author: fjahanian
> Date: Wed Dec  4 14:32:50 2013
> New Revision: 196408
>
> URL: http://llvm.org/viewvc/llvm-project?rev=196408&view=rev
> Log:
> ObjectiveC - Introducing objc_bridge_related attribute
> which specifies couple of (optional) method selectors
> for bridging a CFobject to or from an ObjectiveC
> object. This is wip. // rdsr://15499111
>
> Added:
>     cfe/trunk/test/Parser/objcbridge-related-attribute.m
> Modified:
>     cfe/trunk/include/clang/Basic/Attr.td
>     cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
>     cfe/trunk/include/clang/Parse/Parser.h
>     cfe/trunk/include/clang/Sema/AttributeList.h
>     cfe/trunk/lib/Parse/ParseDecl.cpp
>     cfe/trunk/lib/Sema/SemaDeclAttr.cpp
>
> Modified: cfe/trunk/include/clang/Basic/Attr.td
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=196408&r1=196407&r2=196408&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/Attr.td (original)
> +++ cfe/trunk/include/clang/Basic/Attr.td Wed Dec  4 14:32:50 2013
> @@ -615,6 +615,15 @@ def ObjCBridgeMutable : InheritableAttr
>    let Args = [IdentifierArgument<"BridgedType">];
>  }
>
> +def ObjCBridgeRelated : InheritableAttr {
> +  let Spellings = [GNU<"objc_bridge_related">];
> +  let Subjects = SubjectList<[Record], ErrorDiag>;
> +  let Args = [IdentifierArgument<"RelatedClass">,
> +          IdentifierArgument<"ClassMethod">,
> +          IdentifierArgument<"InstanceMethod">];
> + let HasCustomParsing = 1;
> +}
> +
>  def NSReturnsRetained : InheritableAttr {
>    let Spellings = [GNU<"ns_returns_retained">];
>  //  let Subjects = SubjectList<[ObjCMethod, ObjCProperty, Function]>;
>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=196408&r1=196407&r2=196408&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
> +++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Wed Dec  4 14:32:50 2013
> @@ -753,6 +753,13 @@ def err_zero_version : Error<
>    "version number must have non-zero major, minor, or sub-minor version">;
>  def err_availability_expected_platform : Error<
>    "expected a platform name, e.g., 'macosx'">;
> +
> +// objc_bridge_related attribute
> +def err_objcbridge_related_expected_related_class : Error<
> +  "expected a related ObjectiveC class name, e.g., 'NSColor'">;
> +def err_objcbridge_related_selector_name : Error<
> +  "expected a class method selector with single argument, e.g., 'colorWithCGColor:'">;
> +
>  def err_availability_expected_change : Error<
>    "expected 'introduced', 'deprecated', or 'obsoleted'">;
>  def err_availability_unknown_change : Error<
>
> Modified: cfe/trunk/include/clang/Parse/Parser.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=196408&r1=196407&r2=196408&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Parse/Parser.h (original)
> +++ cfe/trunk/include/clang/Parse/Parser.h Wed Dec  4 14:32:50 2013
> @@ -2003,6 +2003,11 @@ private:
>                                    SourceLocation AvailabilityLoc,
>                                    ParsedAttributes &attrs,
>                                    SourceLocation *endLoc);
> +
> +  void ParseObjCBridgeRelatedAttribute(IdentifierInfo &ObjCBridgeRelated,
> +                                       SourceLocation ObjCBridgeRelatedLoc,
> +                                       ParsedAttributes &attrs,
> +                                       SourceLocation *endLoc);
>
>    bool IsThreadSafetyAttribute(StringRef AttrName);
>    void ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
>
> Modified: cfe/trunk/include/clang/Sema/AttributeList.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AttributeList.h?rev=196408&r1=196407&r2=196408&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Sema/AttributeList.h (original)
> +++ cfe/trunk/include/clang/Sema/AttributeList.h Wed Dec  4 14:32:50 2013
> @@ -245,6 +245,26 @@ private:
>      AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
>    }
>
> +  /// Constructor for objc_bridge_related attributes.
> +  AttributeList(IdentifierInfo *attrName, SourceRange attrRange,
> +                IdentifierInfo *scopeName, SourceLocation scopeLoc,
> +                IdentifierLoc *Parm1,
> +                IdentifierLoc *Parm2,
> +                IdentifierLoc *Parm3,
> +                Syntax syntaxUsed)
> +  : AttrName(attrName), ScopeName(scopeName), AttrRange(attrRange),
> +    ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(3), SyntaxUsed(syntaxUsed),
> +    Invalid(false), UsedAsTypeAttr(false), IsAvailability(false),
> +    IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false),
> +    NextInPosition(0), NextInPool(0) {
> +    ArgsVector Args;
> +    Args.push_back(Parm1);
> +    Args.push_back(Parm2);
> +    Args.push_back(Parm3);
> +    memcpy(getArgsBuffer(), &Args[0], 3 * sizeof(ArgsUnion));
> +    AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
> +  }
> +
>    /// Constructor for type_tag_for_datatype attribute.
>    AttributeList(IdentifierInfo *attrName, SourceRange attrRange,
>                  IdentifierInfo *scopeName, SourceLocation scopeLoc,
> @@ -609,6 +629,20 @@ public:
>                                            syntax));
>    }
>
> +  AttributeList *create(IdentifierInfo *attrName, SourceRange attrRange,
> +                        IdentifierInfo *scopeName, SourceLocation scopeLoc,
> +                        IdentifierLoc *Param1,
> +                        IdentifierLoc *Param2,
> +                        IdentifierLoc *Param3,
> +                        AttributeList::Syntax syntax) {
> +    size_t size = sizeof(AttributeList) + 3 * sizeof(ArgsUnion);
> +    void *memory = allocate(size);
> +    return add(new (memory) AttributeList(attrName, attrRange,
> +                                          scopeName, scopeLoc,
> +                                          Param1, Param2, Param3,
> +                                          syntax));
> +  }
> +
>    AttributeList *createIntegerAttribute(ASTContext &C, IdentifierInfo *Name,
>                                          SourceLocation TokLoc, int Arg);
>
> @@ -768,6 +802,20 @@ public:
>      add(attr);
>      return attr;
>    }
> +
> +  /// Add objc_bridge_related attribute.
> +  AttributeList *addNew(IdentifierInfo *attrName, SourceRange attrRange,
> +                        IdentifierInfo *scopeName, SourceLocation scopeLoc,
> +                        IdentifierLoc *Param1,
> +                        IdentifierLoc *Param2,
> +                        IdentifierLoc *Param3,
> +                        AttributeList::Syntax syntax) {
> +    AttributeList *attr =
> +      pool.create(attrName, attrRange, scopeName, scopeLoc,
> +                  Param1, Param2, Param3, syntax);
> +    add(attr);
> +    return attr;
> +  }
>
>    /// Add type_tag_for_datatype attribute.
>    AttributeList *addNewTypeTagForDatatype(
>
> Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=196408&r1=196407&r2=196408&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
> +++ cfe/trunk/lib/Parse/ParseDecl.cpp Wed Dec  4 14:32:50 2013
> @@ -259,6 +259,12 @@ void Parser::ParseGNUAttributeArgs(Ident
>      ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
>      return;
>    }
> +
> +  if (AttrKind == AttributeList::AT_ObjCBridgeRelated) {
> +    ParseObjCBridgeRelatedAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
> +    return;
> +  }
> +
>    // Thread safety attributes are parsed in an unevaluated context.
>    // FIXME: Share the bulk of the parsing code here and just pull out
>    // the unevaluated context.
> @@ -959,6 +965,90 @@ void Parser::ParseAvailabilityAttribute(
>                 AttributeList::AS_GNU);
>  }
>
> +/// \brief Parse the contents of the "objc_bridge_related" attribute.
> +/// objc_bridge_related '(' related_class ',' opt-class_method ',' opt-instance_method ')'
> +/// related_class:
> +///     Identifier
> +///
> +/// opt-class_method:
> +///     Identifier: | <empty>
> +///
> +/// opt-instance_method:
> +///     Identifier | <empty>
> +///
> +void Parser::ParseObjCBridgeRelatedAttribute(IdentifierInfo &ObjCBridgeRelated,
> +                                SourceLocation ObjCBridgeRelatedLoc,
> +                                ParsedAttributes &attrs,
> +                                SourceLocation *endLoc) {
> +  // Opening '('.
> +  BalancedDelimiterTracker T(*this, tok::l_paren);
> +  if (T.consumeOpen()) {
> +    Diag(Tok, diag::err_expected_lparen);
> +    return;
> +  }
> +
> +  // Parse the related class name.
> +  if (Tok.isNot(tok::identifier)) {
> +    Diag(Tok, diag::err_objcbridge_related_expected_related_class);
> +    SkipUntil(tok::r_paren, StopAtSemi);
> +    return;
> +  }
> +  IdentifierLoc *RelatedClass = ParseIdentifierLoc();
> +  if (Tok.isNot(tok::comma)) {
> +    Diag(Tok, diag::err_expected_comma);
> +    SkipUntil(tok::r_paren, StopAtSemi);
> +    return;
> +  }
> +  ConsumeToken();
> +
> +  // Parse optional class method name.
> +  IdentifierLoc *ClassMethod = 0;
> +  if (Tok.is(tok::identifier)) {
> +    ClassMethod = ParseIdentifierLoc();
> +    if (Tok.isNot(tok::colon)) {
> +      Diag(Tok, diag::err_objcbridge_related_selector_name);
> +      SkipUntil(tok::r_paren, StopAtSemi);
> +      return;
> +    }
> +    ConsumeToken();
> +  }
> +  if (Tok.isNot(tok::comma)) {
> +    if (Tok.is(tok::colon))
> +      Diag(Tok, diag::err_objcbridge_related_selector_name);
> +    else
> +      Diag(Tok, diag::err_expected_comma);
> +    SkipUntil(tok::r_paren, StopAtSemi);
> +    return;
> +  }
> +  ConsumeToken();
> +
> +  // Parse optional instance method name.
> +  IdentifierLoc *InstanceMethod = 0;
> +  if (Tok.is(tok::identifier))
> +    InstanceMethod = ParseIdentifierLoc();
> +  else if (Tok.isNot(tok::r_paren)) {
> +    Diag(Tok, diag::err_expected_rparen);
> +    SkipUntil(tok::r_paren, StopAtSemi);
> +    return;
> +  }
> +
> +  // Closing ')'.
> +  if (T.consumeClose())
> +    return;
> +
> +  if (endLoc)
> +    *endLoc = T.getCloseLocation();
> +
> +  // Record this attribute
> +  attrs.addNew(&ObjCBridgeRelated,
> +               SourceRange(ObjCBridgeRelatedLoc, T.getCloseLocation()),
> +               0, ObjCBridgeRelatedLoc,
> +               RelatedClass,
> +               ClassMethod,
> +               InstanceMethod,
> +               AttributeList::AS_GNU);
> +
> +}
>
>  // Late Parsed Attributes:
>  // See other examples of late parsing in lib/Parse/ParseCXXInlineMethods
>
> Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=196408&r1=196407&r2=196408&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Wed Dec  4 14:32:50 2013
> @@ -3713,6 +3713,24 @@ static void handleObjCBridgeMutableAttr(
>                              Attr.getAttributeSpellingListIndex()));
>  }
>
> +static void handleObjCBridgeRelatedAttr(Sema &S, Scope *Sc, Decl *D,
> +                                 const AttributeList &Attr) {

Because you have custom parsing, none of the common attribute handling
is taken care of for you. You'll have to add subject and argument
verification here.

> +  IdentifierInfo *RelatedClass =
> +    Attr.isArgIdent(0) ? Attr.getArgAsIdent(0)->Ident : 0;
> +  if (!RelatedClass) {
> +    S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << Attr.getName() << 0;
> +    return;
> +  }
> +  IdentifierInfo *ClassMethod =
> +    Attr.getArgAsIdent(1) ? Attr.getArgAsIdent(1)->Ident : 0;
> +  IdentifierInfo *InstanceMethod =
> +    Attr.getArgAsIdent(2) ? Attr.getArgAsIdent(2)->Ident : 0;
> +  D->addAttr(::new (S.Context)
> +             ObjCBridgeRelatedAttr(Attr.getRange(), S.Context, RelatedClass,
> +                                   ClassMethod, InstanceMethod,
> +                                   Attr.getAttributeSpellingListIndex()));
> +}
> +
>  static void handleObjCDesignatedInitializer(Sema &S, Decl *D,
>                                              const AttributeList &Attr) {
>    SourceLocation Loc = Attr.getLoc();
> @@ -3986,6 +4004,9 @@ static void ProcessDeclAttribute(Sema &S
>
>    case AttributeList::AT_ObjCBridgeMutable:
>      handleObjCBridgeMutableAttr(S, scope, D, Attr); break;
> +
> +  case AttributeList::AT_ObjCBridgeRelated:
> +    handleObjCBridgeRelatedAttr(S, scope, D, Attr); break;
>
>    case AttributeList::AT_ObjCDesignatedInitializer:
>      handleObjCDesignatedInitializer(S, D, Attr); break;
>
> Added: cfe/trunk/test/Parser/objcbridge-related-attribute.m
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/objcbridge-related-attribute.m?rev=196408&view=auto
> ==============================================================================
> --- cfe/trunk/test/Parser/objcbridge-related-attribute.m (added)
> +++ cfe/trunk/test/Parser/objcbridge-related-attribute.m Wed Dec  4 14:32:50 2013
> @@ -0,0 +1,15 @@
> +// RUN: %clang_cc1 -verify -fsyntax-only %s
> +// rdar://15499111
> +
> +typedef struct __attribute__((objc_bridge_related(NSColor,colorWithCGColor:,CGColor))) CGColor *CGColorRefOk;
> +typedef struct __attribute__((objc_bridge_related(NSColor,,CGColor))) CGColor *CGColorRef1Ok;
> +typedef struct __attribute__((objc_bridge_related(NSColor,,))) CGColor *CGColorRef2Ok;
> +typedef struct __attribute__((objc_bridge_related(NSColor,colorWithCGColor:,))) CGColor *CGColorRef3Ok;
> +
> +typedef struct __attribute__((objc_bridge_related(,colorWithCGColor:,CGColor))) CGColor *CGColorRef1NotOk; // expected-error {{expected a related ObjectiveC class name, e.g., 'NSColor'}}
> +typedef struct __attribute__((objc_bridge_related(NSColor,colorWithCGColor,CGColor))) CGColor *CGColorRef2NotOk; // expected-error {{expected a class method selector with single argument, e.g., 'colorWithCGColor:'}}
> +typedef struct __attribute__((objc_bridge_related(NSColor,colorWithCGColor::,CGColor))) CGColor *CGColorRef3NotOk; // expected-error {{expected a class method selector with single argument, e.g., 'colorWithCGColor:'}}
> +typedef struct __attribute__((objc_bridge_related(12,colorWithCGColor:,CGColor))) CGColor *CGColorRef4NotOk; // expected-error {{expected a related ObjectiveC class name, e.g., 'NSColor'}}
> +typedef struct __attribute__((objc_bridge_related(NSColor,+:,CGColor))) CGColor *CGColorRef5NotOk; // expected-error {{expected ','}}
> +typedef struct __attribute__((objc_bridge_related(NSColor,colorWithCGColor:,+))) CGColor *CGColorRef6NotOk; // expected-error {{expected ')'}}
> +
>

Sema tests are missing (subject, number of arguments, type of arguments, etc).

~Aaron



More information about the cfe-commits mailing list