diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 9eab140239af0..800e427c087de 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2040,7 +2040,7 @@ def ObjCBridgeRelated : InheritableAttr { def NSErrorDomain : InheritableAttr { let Spellings = [GNU<"ns_error_domain">]; let Subjects = SubjectList<[Enum], ErrorDiag>; - let Args = [DeclArgument]; + let Args = [IdentifierArgument<"ErrorDomain">]; let Documentation = [NSErrorDomainDocs]; } diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp index 021735c714be6..3b370ca5df954 100644 --- a/clang/lib/Sema/SemaAPINotes.cpp +++ b/clang/lib/Sema/SemaAPINotes.cpp @@ -348,22 +348,11 @@ static void ProcessAPINotes(Sema &S, Decl *D, // ns_error_domain if (auto nsErrorDomain = info.getNSErrorDomain()) { - handleAPINotedAttribute( - S, D, !nsErrorDomain->empty(), metadata, [&]() -> NSErrorDomainAttr * { - LookupResult lookupResult( - S, DeclarationName(&S.Context.Idents.get(*nsErrorDomain)), - SourceLocation(), Sema::LookupNameKind::LookupOrdinaryName); - S.LookupName(lookupResult, S.TUScope); - auto *VD = lookupResult.getAsSingle(); - - if (!VD) { - S.Diag(D->getLocation(), diag::err_nserrordomain_invalid_decl) << 0; - return nullptr; - } - - return new (S.Context) - NSErrorDomainAttr(S.Context, getDummyAttrInfo(), VD); - }); + handleAPINotedAttribute(S, D, !nsErrorDomain->empty(), + metadata, [&] { + return new (S.Context) NSErrorDomainAttr( + S.Context, getDummyAttrInfo(), &S.Context.Idents.get(*nsErrorDomain)); + }); } ProcessAPINotes(S, D, static_cast(info), diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index d349e30f97066..ce35ca37c8f03 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5509,29 +5509,37 @@ static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, 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(AL.getArgAsExpr(0)); - if (!DRE) { - S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 0; +static void handleNSErrorDomain(Sema &S, Decl *D, const ParsedAttr &Attr) { + if (!isa(D)) { + S.Diag(D->getBeginLoc(), diag::err_nserrordomain_invalid_decl) + << 0; 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)->getBeginLoc(); - auto *VD = dyn_cast(DRE->getDecl()); - if (!VD) { - S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 1 << DRE->getDecl(); + S.Diag(loc, diag::err_nserrordomain_invalid_decl) << 0; return; } - if (!isNSStringType(VD->getType(), S.Context) && - !isCFStringType(VD->getType(), S.Context)) { - S.Diag(Loc, diag::err_nserrordomain_wrong_type) << VD; + // 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()) { + S.Diag(identLoc->Loc, diag::err_nserrordomain_invalid_decl) + << 1 << identLoc->Ident; return; } - D->addAttr(::new (S.Context) NSErrorDomainAttr(S.Context, AL, VD)); + D->addAttr(::new (S.Context) + NSErrorDomainAttr(S.Context, Attr, identLoc->Ident)); } static void handleObjCBridgeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { diff --git a/clang/test/Sema/ns_error_enum.m b/clang/test/Sema/ns_error_enum.m index 895f9b8b3356a..c7c0b270b1abf 100644 --- a/clang/test/Sema/ns_error_enum.m +++ b/clang/test/Sema/ns_error_enum.m @@ -53,7 +53,6 @@ typedef NS_ERROR_ENUM(unsigned char, MyCFTypedefErrorEnum, MyCFTypedefErrorDomai extern char *const WrongErrorDomainType; enum __attribute__((ns_error_domain(WrongErrorDomainType))) MyWrongErrorDomainType { MyWrongErrorDomain }; -// expected-error@-1{{domain argument 'WrongErrorDomainType' does not point to an NSString or CFString constant}} struct __attribute__((ns_error_domain(MyErrorDomain))) MyStructWithErrorDomain {}; // expected-error@-1{{'ns_error_domain' attribute only applies to enums}} @@ -68,7 +67,7 @@ typedef NS_ERROR_ENUM(unsigned char, MyCFTypedefErrorEnum, MyCFTypedefErrorDomai // 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'}} + // expected-error@-1{{domain argument 'InvalidDomain' does not refer to global constant}} MyErrFirstInvalid, MyErrSecondInvalid, };