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

Commit b624ed1

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 b624ed1

File tree

5 files changed

+101
-0
lines changed

5 files changed

+101
-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: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7533,6 +7533,14 @@ 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 "
7539+
"%select{enums, structs, and unions|enums, structs, unions, and classes}0">;
7540+
def err_nserrordomain_invalid_decl : Error<
7541+
"domain argument %0 does not refer to global constant">;
7542+
def err_nserrordomain_requires_identifier : Error<
7543+
"domain argument must be an identifier">;
75367544

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

lib/Sema/SemaDeclAttr.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4263,6 +4263,40 @@ 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+
<< S.getLangOpts().CPlusPlus;
4270+
return;
4271+
}
4272+
IdentifierLoc *identLoc =
4273+
Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr;
4274+
if (!identLoc || !identLoc->Ident) {
4275+
// Try to locate the argument directly
4276+
SourceLocation loc = Attr.getLoc();
4277+
if (Attr.isArgExpr(0) && Attr.getArgAsExpr(0))
4278+
loc = Attr.getArgAsExpr(0)->getLocStart();
4279+
4280+
S.Diag(loc, diag::err_nserrordomain_requires_identifier);
4281+
return;
4282+
}
4283+
4284+
// Verify that the identifier is a valid decl in the C decl namespace
4285+
LookupResult lookupResult(S, DeclarationName(identLoc->Ident),
4286+
SourceLocation(),
4287+
Sema::LookupNameKind::LookupOrdinaryName);
4288+
if (!S.LookupName(lookupResult, S.TUScope) ||
4289+
!lookupResult.getAsSingle<VarDecl>()) {
4290+
S.Diag(identLoc->Loc, diag::err_nserrordomain_invalid_decl)
4291+
<< identLoc->Ident;
4292+
return;
4293+
}
4294+
4295+
D->addAttr(::new (S.Context)
4296+
NSErrorDomainAttr(Attr.getRange(), S.Context, identLoc->Ident,
4297+
Attr.getAttributeSpellingListIndex()));
4298+
}
4299+
42664300
static void handleCFAuditedTransferAttr(Sema &S, Decl *D,
42674301
const AttributeList &Attr) {
42684302
if (checkAttrMutualExclusion<CFUnknownTransferAttr>(S, D, Attr.getRange(),
@@ -5560,6 +5594,10 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
55605594
case AttributeList::AT_ObjCBoxable:
55615595
handleObjCBoxable(S, D, Attr);
55625596
break;
5597+
5598+
case AttributeList::AT_NSErrorDomain:
5599+
handleNSErrorDomain(S, D, Attr);
5600+
break;
55635601

55645602
case AttributeList::AT_CFAuditedTransfer:
55655603
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' does not refer to global constant}}
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 enums, structs, and unions}}
39+
40+
void foo() {}
41+
typedef NS_ERROR_ENUM(unsigned char, MyErrorEnumInvalidFunction, foo);
42+
// expected-error@-1{{domain argument 'foo' does not refer to global constant}}

0 commit comments

Comments
 (0)