This revision was automatically updated to reflect the committed changes. Closed by commit rGa5b8757506b0: Introduce ns_error_domain attribute. (authored by MForster, committed by gribozavr).
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D84005/new/ https://reviews.llvm.org/D84005 Files: clang/include/clang/Basic/Attr.td clang/include/clang/Basic/AttrDocs.td clang/include/clang/Basic/DiagnosticSemaKinds.td clang/lib/Sema/SemaDeclAttr.cpp clang/test/AST/ast-print-attr.c clang/test/Misc/pragma-attribute-supported-attributes-list.test clang/test/Sema/ns_error_enum.m clang/utils/TableGen/ClangAttrEmitter.cpp
Index: clang/utils/TableGen/ClangAttrEmitter.cpp =================================================================== --- clang/utils/TableGen/ClangAttrEmitter.cpp +++ clang/utils/TableGen/ClangAttrEmitter.cpp @@ -329,6 +329,8 @@ // empty string but are then recorded as a nullptr. OS << "\" << (get" << getUpperName() << "() ? get" << getUpperName() << "()->getName() : \"\") << \""; + else if (type == "VarDecl *") + OS << "\" << get" << getUpperName() << "()->getName() << \""; else if (type == "TypeSourceInfo *") OS << "\" << get" << getUpperName() << "().getAsString() << \""; else if (type == "ParamIdx") Index: clang/test/Sema/ns_error_enum.m =================================================================== --- /dev/null +++ clang/test/Sema/ns_error_enum.m @@ -0,0 +1,66 @@ +// RUN: %clang_cc1 -verify %s -x objective-c +// RUN: %clang_cc1 -verify %s -x objective-c++ + + +#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, +}; + +@interface NSString +@end + +extern NSString *const MyErrorDomain; +typedef NS_ERROR_ENUM(unsigned char, MyErrorEnum, MyErrorDomain) { + MyErrFirst, + MyErrSecond, +}; + +typedef NSString *const NsErrorDomain; +extern NsErrorDomain MyTypedefErrorDomain; +typedef NS_ERROR_ENUM(unsigned char, MyTypedefErrorEnum, MyTypedefErrorDomain) { + MyTypedefErrFirst, + MyTypedefErrSecond, +}; + +extern char *const WrongErrorDomainType; +enum __attribute__((ns_error_domain(WrongErrorDomainType))) MyWrongErrorDomainType { MyWrongErrorDomain }; +// expected-error@-1{{domain argument 'WrongErrorDomainType' does not point to an NSString constant}} + +struct __attribute__((ns_error_domain(MyErrorDomain))) MyStructWithErrorDomain {}; +// expected-error@-1{{'ns_error_domain' attribute only applies to enums}} + +int __attribute__((ns_error_domain(MyErrorDomain))) NotTagDecl; + // expected-error@-1{{'ns_error_domain' attribute only applies to enums}} + +enum __attribute__((ns_error_domain())) NoArg { NoArgError }; +// expected-error@-1{{'ns_error_domain' attribute takes one argument}} + +enum __attribute__((ns_error_domain(MyErrorDomain, MyErrorDomain))) TwoArgs { TwoArgsError }; +// expected-error@-1{{'ns_error_domain' attribute takes one argument}} + +typedef NS_ERROR_ENUM(unsigned char, MyErrorEnumInvalid, InvalidDomain) { + // expected-error@-1{{use of undeclared identifier 'InvalidDomain'}} + MyErrFirstInvalid, + MyErrSecondInvalid, +}; + +typedef NS_ERROR_ENUM(unsigned char, MyErrorEnumInvalid, "domain-string"); + // expected-error@-1{{domain argument does not refer to global constant}} + +void foo() {} +typedef NS_ERROR_ENUM(unsigned char, MyErrorEnumInvalidFunction, foo); + // expected-error@-1{{domain argument 'foo' does not refer to global constant}} Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test =================================================================== --- clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -80,6 +80,7 @@ // CHECK-NEXT: MipsShortCall (SubjectMatchRule_function) // CHECK-NEXT: NSConsumed (SubjectMatchRule_variable_is_parameter) // CHECK-NEXT: NSConsumesSelf (SubjectMatchRule_objc_method) +// CHECK-NEXT: NSErrorDomain (SubjectMatchRule_enum) // CHECK-NEXT: Naked (SubjectMatchRule_function) // CHECK-NEXT: NoBuiltin (SubjectMatchRule_function) // CHECK-NEXT: NoCommon (SubjectMatchRule_variable) Index: clang/test/AST/ast-print-attr.c =================================================================== --- clang/test/AST/ast-print-attr.c +++ clang/test/AST/ast-print-attr.c @@ -15,3 +15,14 @@ int fun_asm() asm("test"); // CHECK: int var_asm asm("test"); int var_asm asm("test"); + + +@interface NSString +@end + +extern NSString *const MyErrorDomain; +// CHECK: enum __attribute__((ns_error_domain(MyErrorDomain))) MyErrorEnum { +enum __attribute__((ns_error_domain(MyErrorDomain))) MyErrorEnum { + MyErrFirst, + MyErrSecond, +}; Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -21,6 +21,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/Mangle.h" #include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/Type.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetBuiltins.h" @@ -30,12 +31,15 @@ #include "clang/Sema/DelayedDiagnostic.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/ParsedAttr.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" using namespace clang; using namespace sema; @@ -5322,6 +5326,30 @@ D->addAttr(::new (S.Context) ObjCRequiresSuperAttr(S.Context, Attrs)); } +static void handleNSErrorDomain(Sema &S, Decl *D, const ParsedAttr &AL) { + auto *E = AL.getArgAsExpr(0); + auto Loc = E ? E->getBeginLoc() : AL.getLoc(); + + auto *DRE = dyn_cast<DeclRefExpr>(AL.getArgAsExpr(0)); + if (!DRE) { + S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 0; + return; + } + + auto *VD = dyn_cast<VarDecl>(DRE->getDecl()); + if (!VD) { + S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 1 << DRE->getDecl(); + return; + } + + if (!isNSStringType(VD->getType(), S.Context)) { + S.Diag(Loc, diag::err_nserrordomain_wrong_type) << VD; + return; + } + + D->addAttr(::new (S.Context) NSErrorDomainAttr(S.Context, AL, VD)); +} + static void handleObjCBridgeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { IdentifierLoc *Parm = AL.isArgIdent(0) ? AL.getArgAsIdent(0) : nullptr; @@ -7093,6 +7121,9 @@ case ParsedAttr::AT_ObjCBoxable: handleObjCBoxable(S, D, AL); break; + case ParsedAttr::AT_NSErrorDomain: + handleNSErrorDomain(S, D, AL); + break; case ParsedAttr::AT_CFAuditedTransfer: handleSimpleAttributeWithExclusions<CFAuditedTransferAttr, CFUnknownTransferAttr>(S, D, AL); Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9476,6 +9476,11 @@ def err_nsreturns_retained_attribute_mismatch : Error< "overriding method has mismatched ns_returns_%select{not_retained|retained}0" " attributes">; +def err_nserrordomain_invalid_decl : Error< + "domain argument %select{|%1 }0does not refer to global constant">; +def err_nserrordomain_wrong_type : Error< + "domain argument %0 does not point to an NSString constant">; + def warn_nsconsumed_attribute_mismatch : Warning< err_nsconsumed_attribute_mismatch.Text>, InGroup<NSConsumedMismatch>; def warn_nsreturns_retained_attribute_mismatch : Warning< Index: clang/include/clang/Basic/AttrDocs.td =================================================================== --- clang/include/clang/Basic/AttrDocs.td +++ clang/include/clang/Basic/AttrDocs.td @@ -3339,6 +3339,38 @@ }]; } +def NSErrorDomainDocs : Documentation { + let Category = DocCatDecl; + let Content = [{ +In Cocoa frameworks in Objective-C, one can group related error codes in enums +and categorize these enums with error domains. + +The ``ns_error_domain`` attribute indicates a global ``NSString`` constant +representing the error domain that an error code belongs to. For pointer +uniqueness and code size this is a constant symbol, not a literal. + +The domain and error code need to be used together. The ``ns_error_domain`` +attribute links error codes to their domain at the source level. + +This metadata is useful for documentation purposes, for static analysis, and for +improving interoperability between Objective-C and Swift. It is not used for +code generation in Objective-C. + +For example: + + .. code-block:: objc + + #define NS_ERROR_ENUM(_type, _name, _domain) \ + enum _name : _type _name; enum __attribute__((ns_error_domain(_domain))) _name : _type + + extern NSString *const MyErrorDomain; + typedef NS_ERROR_ENUM(unsigned char, MyErrorEnum, MyErrorDomain) { + MyErrFirst, + MyErrSecond, + }; + }]; +} + def OMPDeclareSimdDocs : Documentation { let Category = DocCatFunction; let Heading = "#pragma omp declare simd"; Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -1878,6 +1878,13 @@ let Documentation = [Undocumented]; } +def NSErrorDomain : InheritableAttr { + let Spellings = [GNU<"ns_error_domain">]; + let Subjects = SubjectList<[Enum], ErrorDiag>; + let Args = [DeclArgument<Var, "ErrorDomain">]; + let Documentation = [NSErrorDomainDocs]; +} + def NSReturnsRetained : DeclOrTypeAttr { let Spellings = [Clang<"ns_returns_retained">]; // let Subjects = SubjectList<[ObjCMethod, ObjCProperty, Function]>;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits