Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Introduce ns_error_domain attribute. #5

Merged
merged 1 commit into from
Feb 3, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -1115,6 +1115,12 @@ def ObjCBridgeRelated : InheritableAttr {
let Documentation = [Undocumented];
}

def NSErrorDomain : Attr {
let Spellings = [GNU<"ns_error_domain">];
let Args = [IdentifierArgument<"ErrorDomain">];
let Documentation = [NSErrorDomainDocs];
}

def NSReturnsRetained : InheritableAttr {
let Spellings = [GNU<"ns_returns_retained">];
// let Subjects = SubjectList<[ObjCMethod, ObjCProperty, Function]>;
Expand Down
7 changes: 7 additions & 0 deletions include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -1758,6 +1758,13 @@ arguments, with arbitrary offsets.
}];
}

def NSErrorDomainDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
The ``ns_error_domain`` attribute indicates a global constant representing the error domain.
}];
}

def SwiftDocs : DocumentationCategory<"Controlling Swift Import"> {
let Content = [{
Clang supports additional attributes for controlling how APIs are imported into Swift.
Expand Down
8 changes: 8 additions & 0 deletions include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -7533,6 +7533,14 @@ def err_nsconsumed_attribute_mismatch : Error<
def err_nsreturns_retained_attribute_mismatch : Error<
"overriding method has mismatched ns_returns_%select{not_retained|retained}0"
" attributes">;

def err_nserrordomain_not_tagdecl : Error<
"ns_error_domain attribute only valid on "
"%select{enums, structs, and unions|enums, structs, unions, and classes}0">;
def err_nserrordomain_invalid_decl : Error<
"domain argument %0 does not refer to global constant">;
def err_nserrordomain_requires_identifier : Error<
"domain argument must be an identifier">;

def note_getter_unavailable : Note<
"or because setter is declared here, but no getter method %0 is found">;
Expand Down
38 changes: 38 additions & 0 deletions lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4263,6 +4263,40 @@ 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)
<< S.getLangOpts().CPlusPlus;
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) ||
!lookupResult.getAsSingle<VarDecl>()) {
S.Diag(identLoc->Loc, diag::err_nserrordomain_invalid_decl)
<< identLoc->Ident;
return;
}

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.getRange(),
Expand Down Expand Up @@ -5560,6 +5594,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);
Expand Down
42 changes: 42 additions & 0 deletions test/Analysis/ns_error_enum.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// 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' does not refer to global constant}}
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 enums, structs, and unions}}

void foo() {}
typedef NS_ERROR_ENUM(unsigned char, MyErrorEnumInvalidFunction, foo);
// expected-error@-1{{domain argument 'foo' does not refer to global constant}}