-
Notifications
You must be signed in to change notification settings - Fork 159
Introduce ns_error_domain attribute. #3
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4057,6 +4057,38 @@ static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, | |
attr.getAttributeSpellingListIndex())); | ||
} | ||
|
||
static void handleNSErrorDomain(Sema &S, Decl *D, const AttributeList &Attr) { | ||
if (!isa<TagDecl>(D)) { | ||
S.Diag(D->getLocStart(), diag::err_nserrordomain_not_tagdecl); | ||
return; | ||
} | ||
IdentifierLoc *identLoc = | ||
Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr; | ||
if (!identLoc || !identLoc->Ident) { | ||
// Try to locate the argument directly | ||
SourceLocation loc = Attr.getLoc(); | ||
if (Attr.isArgExpr(0) && Attr.getArgAsExpr(0)) | ||
loc = Attr.getArgAsExpr(0)->getLocStart(); | ||
|
||
S.Diag(loc, diag::err_nserrordomain_requires_identifier); | ||
return; | ||
} | ||
|
||
// Verify that the identifier is a valid decl in the C decl namespace | ||
LookupResult lookupResult(S, DeclarationName(identLoc->Ident), | ||
SourceLocation(), | ||
Sema::LookupNameKind::LookupOrdinaryName); | ||
if (!S.LookupName(lookupResult, S.TUScope)) { | ||
S.Diag(identLoc->Loc, diag::err_nserrordomain_invalid_decl) | ||
<< identLoc->Ident; | ||
return; | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps you should be checking that it's actually a global-scope variable? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ... in which case you could record the declaration in the attribute, rather than just the identifier, so clients don't need to look it up themselves. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I wanted to leave the actual Decl in the attribute, but it didn't seem like I could without modifying the tablegen backend for Attributes. I'm certainly open to doing that, but not sure if it's worth it. Right now, only FunctionDecl and IdentifierInfo are supported, it seems, in ClangAttrEmitter.cpp's "createArgument". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, that's fine |
||
D->addAttr(::new (S.Context) | ||
NSErrorDomainAttr(Attr.getRange(), S.Context, identLoc->Ident, | ||
Attr.getAttributeSpellingListIndex())); | ||
} | ||
|
||
static void handleCFAuditedTransferAttr(Sema &S, Decl *D, | ||
const AttributeList &Attr) { | ||
if (checkAttrMutualExclusion<CFUnknownTransferAttr>(S, D, Attr)) | ||
|
@@ -5197,6 +5229,10 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, | |
case AttributeList::AT_ObjCBoxable: | ||
handleObjCBoxable(S, D, Attr); | ||
break; | ||
|
||
case AttributeList::AT_NSErrorDomain: | ||
handleNSErrorDomain(S, D, Attr); | ||
break; | ||
|
||
case AttributeList::AT_CFAuditedTransfer: | ||
handleCFAuditedTransferAttr(S, D, Attr); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// RUN: %clang_cc1 -verify %s | ||
|
||
#define CF_ENUM(_type, _name) enum _name : _type _name; enum _name : _type | ||
#define NS_ENUM(_type, _name) CF_ENUM(_type, _name) | ||
|
||
#define NS_ERROR_ENUM(_type, _name, _domain) \ | ||
enum _name : _type _name; enum __attribute__((ns_error_domain(_domain))) _name : _type | ||
|
||
typedef NS_ENUM(unsigned, MyEnum) { | ||
MyFirst, | ||
MySecond, | ||
}; | ||
|
||
typedef NS_ENUM(invalidType, MyInvalidEnum) { | ||
// expected-error@-1{{unknown type name 'invalidType'}} | ||
// expected-error@-2{{unknown type name 'invalidType'}} | ||
MyFirstInvalid, | ||
MySecondInvalid, | ||
}; | ||
|
||
const char *MyErrorDomain; | ||
typedef NS_ERROR_ENUM(unsigned char, MyErrorEnum, MyErrorDomain) { | ||
MyErrFirst, | ||
MyErrSecond, | ||
}; | ||
struct __attribute__((ns_error_domain(MyErrorDomain))) MyStructErrorDomain {}; | ||
|
||
typedef NS_ERROR_ENUM(unsigned char, MyErrorEnumInvalid, InvalidDomain) { | ||
// expected-error@-1{{domain argument 'InvalidDomain' not valid top-level declaration}} | ||
MyErrFirstInvalid, | ||
MyErrSecondInvalid, | ||
}; | ||
|
||
typedef NS_ERROR_ENUM(unsigned char, MyErrorEnumInvalid, "domain-string"); | ||
// expected-error@-1{{domain argument must be an identifier}} | ||
|
||
int __attribute__((ns_error_domain(MyErrorDomain))) NotTagDecl; | ||
// expected-error@-1{{ns_error_domain attribute only valid on enum/struct/union/class}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add some documentation here, otherwise it won't get documented anywhere.