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

Commit 5b5a38a

Browse files
committed
Introduce ns_error_domain attribute.
ns_error_domain can be used by, e.g. NS_ERROR_ENUM, in order to identify a global declaration representing the domain constant. Introduces the attribute, Sema handling, diagnostics, and test case.
1 parent 46498da commit 5b5a38a

File tree

5 files changed

+99
-0
lines changed

5 files changed

+99
-0
lines changed

include/clang/Basic/Attr.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,6 +1115,12 @@ def ObjCBridgeRelated : InheritableAttr {
11151115
let Documentation = [Undocumented];
11161116
}
11171117

1118+
def NSErrorDomain : Attr {
1119+
let Spellings = [GNU<"ns_error_domain">];
1120+
let Args = [IdentifierArgument<"ErrorDomain">];
1121+
let Documentation = [NSErrorDomainDocs];
1122+
}
1123+
11181124
def NSReturnsRetained : InheritableAttr {
11191125
let Spellings = [GNU<"ns_returns_retained">];
11201126
// let Subjects = SubjectList<[ObjCMethod, ObjCProperty, Function]>;

include/clang/Basic/AttrDocs.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1758,6 +1758,13 @@ arguments, with arbitrary offsets.
17581758
}];
17591759
}
17601760

1761+
def NSErrorDomainDocs : Documentation {
1762+
let Category = DocCatFunction;
1763+
let Content = [{
1764+
The ``ns_error_domain`` attribute indicates a global constant representing the error domain.
1765+
}];
1766+
}
1767+
17611768
def SwiftDocs : DocumentationCategory<"Controlling Swift Import"> {
17621769
let Content = [{
17631770
Clang supports additional attributes for controlling how APIs are imported into Swift.

include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7533,6 +7533,13 @@ def err_nsconsumed_attribute_mismatch : Error<
75337533
def err_nsreturns_retained_attribute_mismatch : Error<
75347534
"overriding method has mismatched ns_returns_%select{not_retained|retained}0"
75357535
" attributes">;
7536+
7537+
def err_nserrordomain_not_tagdecl : Error<
7538+
"ns_error_domain attribute only valid on enum/struct/union/class">;
7539+
def err_nserrordomain_invalid_decl : Error<
7540+
"domain argument %0 not valid top-level declaration">;
7541+
def err_nserrordomain_requires_identifier : Error<
7542+
"domain argument must be an identifier">;
75367543

75377544
def note_getter_unavailable : Note<
75387545
"or because setter is declared here, but no getter method %0 is found">;

lib/Sema/SemaDeclAttr.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4263,6 +4263,39 @@ static void handleObjCRequiresSuperAttr(Sema &S, Decl *D,
42634263
attr.getAttributeSpellingListIndex()));
42644264
}
42654265

4266+
static void handleNSErrorDomain(Sema &S, Decl *D, const AttributeList &Attr) {
4267+
if (!isa<TagDecl>(D)) {
4268+
S.Diag(D->getLocStart(), diag::err_nserrordomain_not_tagdecl);
4269+
return;
4270+
}
4271+
IdentifierLoc *identLoc =
4272+
Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr;
4273+
if (!identLoc || !identLoc->Ident) {
4274+
// Try to locate the argument directly
4275+
SourceLocation loc = Attr.getLoc();
4276+
if (Attr.isArgExpr(0) && Attr.getArgAsExpr(0))
4277+
loc = Attr.getArgAsExpr(0)->getLocStart();
4278+
4279+
S.Diag(loc, diag::err_nserrordomain_requires_identifier);
4280+
return;
4281+
}
4282+
4283+
// Verify that the identifier is a valid decl in the C decl namespace
4284+
LookupResult lookupResult(S, DeclarationName(identLoc->Ident),
4285+
SourceLocation(),
4286+
Sema::LookupNameKind::LookupOrdinaryName);
4287+
if (!S.LookupName(lookupResult, S.TUScope) ||
4288+
!lookupResult.getAsSingle<VarDecl>()) {
4289+
S.Diag(identLoc->Loc, diag::err_nserrordomain_invalid_decl)
4290+
<< identLoc->Ident;
4291+
return;
4292+
}
4293+
4294+
D->addAttr(::new (S.Context)
4295+
NSErrorDomainAttr(Attr.getRange(), S.Context, identLoc->Ident,
4296+
Attr.getAttributeSpellingListIndex()));
4297+
}
4298+
42664299
static void handleCFAuditedTransferAttr(Sema &S, Decl *D,
42674300
const AttributeList &Attr) {
42684301
if (checkAttrMutualExclusion<CFUnknownTransferAttr>(S, D, Attr.getRange(),
@@ -5560,6 +5593,10 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
55605593
case AttributeList::AT_ObjCBoxable:
55615594
handleObjCBoxable(S, D, Attr);
55625595
break;
5596+
5597+
case AttributeList::AT_NSErrorDomain:
5598+
handleNSErrorDomain(S, D, Attr);
5599+
break;
55635600

55645601
case AttributeList::AT_CFAuditedTransfer:
55655602
handleCFAuditedTransferAttr(S, D, Attr);

test/Analysis/ns_error_enum.m

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// RUN: %clang_cc1 -verify %s
2+
3+
#define CF_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
4+
#define NS_ENUM(_type, _name) CF_ENUM(_type, _name)
5+
6+
#define NS_ERROR_ENUM(_type, _name, _domain) \
7+
enum _name : _type _name; enum __attribute__((ns_error_domain(_domain))) _name : _type
8+
9+
typedef NS_ENUM(unsigned, MyEnum) {
10+
MyFirst,
11+
MySecond,
12+
};
13+
14+
typedef NS_ENUM(invalidType, MyInvalidEnum) {
15+
// expected-error@-1{{unknown type name 'invalidType'}}
16+
// expected-error@-2{{unknown type name 'invalidType'}}
17+
MyFirstInvalid,
18+
MySecondInvalid,
19+
};
20+
21+
const char *MyErrorDomain;
22+
typedef NS_ERROR_ENUM(unsigned char, MyErrorEnum, MyErrorDomain) {
23+
MyErrFirst,
24+
MyErrSecond,
25+
};
26+
struct __attribute__((ns_error_domain(MyErrorDomain))) MyStructErrorDomain {};
27+
28+
typedef NS_ERROR_ENUM(unsigned char, MyErrorEnumInvalid, InvalidDomain) {
29+
// expected-error@-1{{domain argument 'InvalidDomain' not valid top-level declaration}}
30+
MyErrFirstInvalid,
31+
MyErrSecondInvalid,
32+
};
33+
34+
typedef NS_ERROR_ENUM(unsigned char, MyErrorEnumInvalid, "domain-string");
35+
// expected-error@-1{{domain argument must be an identifier}}
36+
37+
int __attribute__((ns_error_domain(MyErrorDomain))) NotTagDecl;
38+
// expected-error@-1{{ns_error_domain attribute only valid on enum/struct/union/class}}
39+
40+
void foo() {}
41+
typedef NS_ERROR_ENUM(unsigned char, MyErrorEnumInvalidFunction, foo);
42+
// expected-error@-1{{domain argument 'foo' not valid top-level declaration}}

0 commit comments

Comments
 (0)