diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h index 699fff9ffb52..5b741c669a53 100644 --- a/clang/include/clang/AST/Attr.h +++ b/clang/include/clang/AST/Attr.h @@ -17,6 +17,7 @@ #include "llvm/Support/Casting.h" #include "llvm/ADT/StringRef.h" #include "clang/Basic/AttrKinds.h" +#include "clang/AST/Type.h" #include #include #include @@ -27,6 +28,7 @@ namespace clang { class IdentifierInfo; class ObjCInterfaceDecl; class Expr; + class QualType; } // Defined in ASTContext.h @@ -286,12 +288,12 @@ public: }; class IBOutletCollectionAttr : public Attr { - const ObjCInterfaceDecl *D; + QualType QT; public: - IBOutletCollectionAttr(const ObjCInterfaceDecl *d = 0) - : Attr(attr::IBOutletCollection), D(d) {} + IBOutletCollectionAttr(QualType qt = QualType()) + : Attr(attr::IBOutletCollection), QT(qt) {} - const ObjCInterfaceDecl *getClass() const { return D; } + QualType getType() const { return QT; } virtual Attr *clone(ASTContext &C) const; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 47c0afffcfac..b243ca0ea53d 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -826,6 +826,8 @@ def err_attributes_are_not_compatible : Error< "%0 and %1 attributes are not compatible">; def err_attribute_wrong_number_arguments : Error< "attribute requires %0 argument(s)">; +def err_iboutletcollection_type : Error< + "invalid type %0 as argument of iboutletcollection attribue">; def err_attribute_missing_parameter_name : Error< "attribute requires unquoted parameter">; def err_attribute_invalid_vector_type : Error<"invalid vector element type %0">; diff --git a/clang/lib/AST/AttrImpl.cpp b/clang/lib/AST/AttrImpl.cpp index dcd3c5bc434b..994d45cf7450 100644 --- a/clang/lib/AST/AttrImpl.cpp +++ b/clang/lib/AST/AttrImpl.cpp @@ -163,7 +163,7 @@ Attr *IBOutletAttr::clone(ASTContext &C) const { } Attr *IBOutletCollectionAttr::clone(ASTContext &C) const { - return ::new (C) IBOutletCollectionAttr(D); + return ::new (C) IBOutletCollectionAttr(QT); } Attr *IBActionAttr::clone(ASTContext &C) const { diff --git a/clang/lib/Frontend/PCHReaderDecl.cpp b/clang/lib/Frontend/PCHReaderDecl.cpp index aa5ce7aad6a0..a581951da72c 100644 --- a/clang/lib/Frontend/PCHReaderDecl.cpp +++ b/clang/lib/Frontend/PCHReaderDecl.cpp @@ -1190,9 +1190,8 @@ Attr *PCHReader::ReadAttributes(llvm::BitstreamCursor &DeclsCursor) { break; case attr::IBOutletCollection: { - ObjCInterfaceDecl *D = - cast_or_null(GetDecl(Record[Idx++])); - New = ::new (*Context) IBOutletCollectionAttr(D); + QualType QT = GetType(Record[Idx++]); + New = ::new (*Context) IBOutletCollectionAttr(QT); break; } diff --git a/clang/lib/Frontend/PCHWriter.cpp b/clang/lib/Frontend/PCHWriter.cpp index 76fd5528dc8f..ac30fd34ccc4 100644 --- a/clang/lib/Frontend/PCHWriter.cpp +++ b/clang/lib/Frontend/PCHWriter.cpp @@ -2051,7 +2051,7 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) { case attr::IBOutletCollection: { const IBOutletCollectionAttr *ICA = cast(Attr); - AddDeclRef(ICA->getClass(), Record); + AddTypeRef(ICA->getType(), Record); break; } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index a234a7379519..1e3405768aeb 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -263,7 +263,7 @@ static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr, Sema &S) { // The iboutletcollection attribute can have zero or one arguments. - if (Attr.getNumArgs() > 1) { + if (Attr.getParameterName() && Attr.getNumArgs() > 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; } @@ -274,9 +274,26 @@ static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr, S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet) << Attr.getName(); return; } - - // FIXME: Eventually accept the type argument. - d->addAttr(::new (S.Context) IBOutletCollectionAttr()); + IdentifierInfo *II = Attr.getParameterName(); + if (!II) + II = &S.Context.Idents.get("id"); + Sema::TypeTy *TypeRep = S.getTypeName(*II, Attr.getLoc(), + S.getScopeForContext(d->getDeclContext()->getParent())); + if (!TypeRep) { + S.Diag(Attr.getLoc(), diag::err_iboutletcollection_type) << II; + return; + } + QualType QT(QualType::getFromOpaquePtr(TypeRep)); + // Diagnose use of non-object type in iboutletcollection attribute. + // FIXME. Gnu attribute extension ignores use of builtin types in + // attributes. So, __attribute__((iboutletcollection(char))) will be + // treated as __attribute__((iboutletcollection())). + if (!QT->isObjCIdType() && !QT->isObjCClassType() && + !QT->isObjCObjectType()) { + S.Diag(Attr.getLoc(), diag::err_iboutletcollection_type) << II; + return; + } + d->addAttr(::new (S.Context) IBOutletCollectionAttr(QT)); } static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { diff --git a/clang/test/SemaObjC/iboutletcollection-attr.m b/clang/test/SemaObjC/iboutletcollection-attr.m new file mode 100644 index 000000000000..cad4d297e5d4 --- /dev/null +++ b/clang/test/SemaObjC/iboutletcollection-attr.m @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -verify %s +// rdar: // 8308053 + +@interface I { + __attribute__((iboutletcollection(I))) id ivar1; + __attribute__((iboutletcollection(id))) id ivar2; + __attribute__((iboutletcollection())) id ivar3; + __attribute__((iboutletcollection)) id ivar4; +} +@property (nonatomic, retain) __attribute__((iboutletcollection(I))) id prop1; +@property (nonatomic, retain) __attribute__((iboutletcollection(id))) id prop2; +@property (nonatomic, retain) __attribute__((iboutletcollection())) id prop3; +@property (nonatomic, retain) __attribute__((iboutletcollection)) id prop4; +@end + +typedef void *PV; +@interface BAD { + __attribute__((iboutletcollection(I, 1))) id ivar1; // expected-error {{attribute requires 1 argument(s)}} + __attribute__((iboutletcollection(B))) id ivar2; // expected-error {{invalid type 'B' as argument of iboutletcollection attribue}} + __attribute__((iboutletcollection(PV))) id ivar3; // // expected-error {{invalid type 'PV' as argument of iboutletcollection attribue}} +} +@property (nonatomic, retain) __attribute__((iboutletcollection(I,2,3))) id prop1; // expected-error {{attribute requires 1 argument(s)}} +@property (nonatomic, retain) __attribute__((iboutletcollection(B))) id prop2; // expected-error {{invalid type 'B' as argument of iboutletcollection attribue}} +@end +