Hi,
Currently, the iboutletcollection and vec_type_hint attributes are parsed
by contorting the normal list-of-expressions parsing logic. For
iboutletcollection, the "type" is parsed manually, by picking out an
identifier followed by an (optional) list of angle-bracketed identifiers,
and the latter is ignored. This is needlessly complex; the attached patch
modifies them to just parse a type as the attribute argument.
The custom handling also breaks parsing for other kinds of attributes which
*don't* take a type argument; for instance, in
"__attribute__((aligned(int)))" we parse and ignore the 'int', and in
"__attribute__((aligned(int(1))))" we reject a valid expression because we
get confused and think it's a type. This is not even bug-compatible with
g++, which does the right thing in these cases.
Other than fixing bugs, this makes one semantic change: when given a
protocol-qualified object type, IBOutletCollectionAttr now stores the full
type (including the protocol list) where it previously just stored the
interface. I've updated the only consumer of this information that I could
find (in libclang).
Please review!
Thanks.
Index: lib/Parse/ParseDecl.cpp
===================================================================
--- lib/Parse/ParseDecl.cpp (revision 193295)
+++ lib/Parse/ParseDecl.cpp (working copy)
@@ -200,6 +200,32 @@
return IL;
}
+void Parser::ParseAttributeWithTypeArg(IdentifierInfo &AttrName,
+ SourceLocation AttrNameLoc,
+ ParsedAttributes &Attrs,
+ SourceLocation *EndLoc) {
+ BalancedDelimiterTracker Parens(*this, tok::l_paren);
+ Parens.consumeOpen();
+
+ TypeResult T;
+ if (Tok.isNot(tok::r_paren))
+ T = ParseTypeName();
+
+ if (Parens.consumeClose())
+ return;
+
+ if (T.isInvalid())
+ return;
+
+ if (T.isUsable())
+ Attrs.addNewTypeAttr(&AttrName,
+ SourceRange(AttrNameLoc, Parens.getCloseLocation()), 0,
+ AttrNameLoc, T.get(), AttributeList::AS_GNU);
+ else
+ Attrs.addNew(&AttrName, SourceRange(AttrNameLoc, Parens.getCloseLocation()),
+ 0, AttrNameLoc, 0, 0, AttributeList::AS_GNU);
+}
+
/// Parse the arguments to a parameterized GNU attribute or
/// a C++11 attribute in "gnu" namespace.
void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
@@ -213,15 +239,18 @@
assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
AttributeList::Kind AttrKind =
- AttributeList::getKind(AttrName, ScopeName, AttributeList::AS_GNU);
+ AttributeList::getKind(AttrName, ScopeName, Syntax);
// Availability attributes have their own grammar.
+ // FIXME: All these cases fail to pass in the syntax and scope, and might be
+ // written as C++11 gnu:: attributes.
if (AttrKind == AttributeList::AT_Availability) {
ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
return;
}
- // Thread safety attributes fit into the FIXME case above, so we
- // just parse the arguments as a list of expressions
+ // Thread safety attributes are parsed in an unevaluated context.
+ // FIXME: Share the bulk of the parsing code here and just pull out
+ // the unevaluated context.
if (IsThreadSafetyAttribute(AttrName->getName())) {
ParseThreadSafetyAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
return;
@@ -231,74 +260,34 @@
ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
return;
}
+ // __attribute__((vec_type_hint)) and iboutletcollection expect a type arg.
+ if (AttrKind == AttributeList::AT_VecTypeHint ||
+ AttrKind == AttributeList::AT_IBOutletCollection) {
+ ParseAttributeWithTypeArg(*AttrName, AttrNameLoc, Attrs, EndLoc);
+ return;
+ }
// Ignore the left paren location for now.
ConsumeParen();
- bool BuiltinType = false;
ArgsVector ArgExprs;
- TypeResult T;
- SourceRange TypeRange;
- bool TypeParsed = false;
-
- switch (Tok.getKind()) {
- case tok::kw_char:
- case tok::kw_wchar_t:
- case tok::kw_char16_t:
- case tok::kw_char32_t:
- case tok::kw_bool:
- case tok::kw_short:
- case tok::kw_int:
- case tok::kw_long:
- case tok::kw___int64:
- case tok::kw___int128:
- case tok::kw_signed:
- case tok::kw_unsigned:
- case tok::kw_float:
- case tok::kw_double:
- case tok::kw_void:
- case tok::kw_typeof:
- // __attribute__(( vec_type_hint(char) ))
- BuiltinType = true;
- T = ParseTypeName(&TypeRange);
- TypeParsed = true;
- break;
-
- case tok::identifier: {
- if (AttrKind == AttributeList::AT_VecTypeHint) {
- T = ParseTypeName(&TypeRange);
- TypeParsed = true;
- break;
- }
-
+ if (Tok.is(tok::identifier)) {
// If this attribute wants an 'identifier' argument, make it so.
- if (attributeHasIdentifierArg(*AttrName))
- ArgExprs.push_back(ParseIdentifierLoc());
+ bool IsIdentifierArg = attributeHasIdentifierArg(*AttrName);
- // __attribute__((iboutletcollection)) expects an identifier then
- // some other (ignored) things.
- if (AttrKind == AttributeList::AT_IBOutletCollection)
- ArgExprs.push_back(ParseIdentifierLoc());
-
// If we don't know how to parse this attribute, but this is the only
// token in this argument, assume it's meant to be an identifier.
if (AttrKind == AttributeList::UnknownAttribute) {
const Token &Next = NextToken();
- if (Next.is(tok::r_paren) || Next.is(tok::comma))
- ArgExprs.push_back(ParseIdentifierLoc());
+ IsIdentifierArg = Next.is(tok::r_paren) || Next.is(tok::comma);
}
- } break;
- default:
- break;
+ if (IsIdentifierArg)
+ ArgExprs.push_back(ParseIdentifierLoc());
}
- bool isInvalid = false;
- bool isParmType = false;
-
- if (!BuiltinType && AttrKind != AttributeList::AT_VecTypeHint &&
- (!ArgExprs.empty() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren))) {
+ if (!ArgExprs.empty() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren)) {
// Eat the comma.
if (!ArgExprs.empty())
ConsumeToken();
@@ -315,49 +304,13 @@
break;
ConsumeToken(); // Eat the comma, move to the next argument
}
- } else if (Tok.is(tok::less) &&
- AttrKind == AttributeList::AT_IBOutletCollection) {
- if (!ExpectAndConsume(tok::less, diag::err_expected_less_after, "<",
- tok::greater)) {
- while (Tok.is(tok::identifier)) {
- ConsumeToken();
- if (Tok.is(tok::greater))
- break;
- if (Tok.is(tok::comma)) {
- ConsumeToken();
- continue;
- }
- }
- if (Tok.isNot(tok::greater))
- Diag(Tok, diag::err_iboutletcollection_with_protocol);
- SkipUntil(tok::r_paren, false, true); // skip until ')'
- }
- } else if (AttrKind == AttributeList::AT_VecTypeHint) {
- if (T.get() && !T.isInvalid())
- isParmType = true;
- else {
- if (Tok.is(tok::identifier))
- ConsumeToken();
- if (TypeParsed)
- isInvalid = true;
- }
}
SourceLocation RParen = Tok.getLocation();
- if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen) &&
- !isInvalid) {
+ if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) {
SourceLocation AttrLoc = ScopeLoc.isValid() ? ScopeLoc : AttrNameLoc;
- if (isParmType) {
- Attrs.addNewTypeAttr(AttrName, SourceRange(AttrLoc, RParen), ScopeName,
- ScopeLoc, T.get(), Syntax);
- } else {
- AttributeList *attr = Attrs.addNew(
- AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc,
- ArgExprs.data(), ArgExprs.size(), Syntax);
- if (BuiltinType &&
- attr->getKind() == AttributeList::AT_IBOutletCollection)
- Diag(Tok, diag::err_iboutletcollection_builtintype);
- }
+ Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc,
+ ArgExprs.data(), ArgExprs.size(), Syntax);
}
}
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp (revision 193289)
+++ lib/Sema/SemaDeclAttr.cpp (working copy)
@@ -1339,33 +1339,37 @@
if (!checkIBOutletCommon(S, D, Attr))
return;
- IdentifierLoc *IL = Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : 0;
- IdentifierInfo *II;
- SourceLocation ILS;
- if (IL) {
- II = IL->Ident;
- ILS = IL->Loc;
- } else {
- II = &S.Context.Idents.get("NSObject");
+ ParsedType PT;
+
+ if (Attr.hasParsedType())
+ PT = Attr.getTypeArg();
+ else {
+ PT = S.getTypeName(S.Context.Idents.get("NSObject"), Attr.getLoc(),
+ S.getScopeForContext(D->getDeclContext()->getParent()));
+ if (!PT) {
+ S.Diag(Attr.getLoc(), diag::err_iboutletcollection_type) << "NSObject";
+ return;
+ }
}
-
- ParsedType 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 = TypeRep.get();
+
+ TypeSourceInfo *TSI = 0;
+ QualType QT = S.GetTypeFromParser(PT, &TSI);
+ SourceLocation QTLoc =
+ TSI ? TSI->getTypeLoc().getLocStart() : SourceLocation();
+
// 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->isObjCObjectType()) {
- S.Diag(Attr.getLoc(), diag::err_iboutletcollection_type) << II;
+ S.Diag(Attr.getLoc(),
+ QT->isBuiltinType() ? diag::err_iboutletcollection_builtintype
+ : diag::err_iboutletcollection_type) << QT;
return;
}
+
D->addAttr(::new (S.Context)
- IBOutletCollectionAttr(Attr.getRange(), S.Context, QT, ILS,
+ IBOutletCollectionAttr(Attr.getRange(), S.Context, QT, QTLoc,
Attr.getAttributeSpellingListIndex()));
}
Index: test/SemaObjC/iboutletcollection-attr.m
===================================================================
--- test/SemaObjC/iboutletcollection-attr.m (revision 193289)
+++ test/SemaObjC/iboutletcollection-attr.m (working copy)
@@ -18,15 +18,15 @@
typedef void *PV;
@interface BAD {
- __attribute__((iboutletcollection(I, 1))) id ivar1; // expected-error {{'iboutletcollection' attribute takes one argument}}
- __attribute__((iboutletcollection(B))) id ivar2; // expected-error {{invalid type 'B' as argument of iboutletcollection attribute}}
- __attribute__((iboutletcollection(PV))) id ivar3; // expected-error {{invalid type 'PV' as argument of iboutletcollection attribute}}
+ __attribute__((iboutletcollection(I, 1))) id ivar1; // expected-error {{expected ')'}} expected-note {{to match}}
+ __attribute__((iboutletcollection(B))) id ivar2; // expected-error {{unknown type name 'B'}}
+ __attribute__((iboutletcollection(PV))) id ivar3; // expected-error {{invalid type 'PV' (aka 'void *') as argument of iboutletcollection attribute}}
__attribute__((iboutletcollection(PV))) void *ivar4; // expected-warning {{instance variable with 'iboutletcollection' attribute must be an object type (invalid 'void *')}}
__attribute__((iboutletcollection(int))) id ivar5; // expected-error {{type argument of iboutletcollection attribute cannot be a builtin type}}
__attribute__((iboutlet)) int ivar6; // expected-warning {{instance variable with 'iboutlet' attribute must be an object type}}
}
-@property (nonatomic, retain) __attribute__((iboutletcollection(I,2,3))) id prop1; // expected-error {{'iboutletcollection' attribute takes one argument}}
-@property (nonatomic, retain) __attribute__((iboutletcollection(B))) id prop2; // expected-error {{invalid type 'B' as argument of iboutletcollection attribute}}
+@property (nonatomic, retain) __attribute__((iboutletcollection(I,2,3))) id prop1; // expected-error {{expected ')'}} expected-note {{to match}}
+@property (nonatomic, retain) __attribute__((iboutletcollection(B))) id prop2; // expected-error {{unknown type name 'B'}}
@property __attribute__((iboutletcollection(BAD))) int prop3; // expected-warning {{property with 'iboutletcollection' attribute must be an object type (invalid 'int')}}
@end
Index: test/Parser/attributes.c
===================================================================
--- test/Parser/attributes.c (revision 193289)
+++ test/Parser/attributes.c (working copy)
@@ -58,7 +58,7 @@
void __attribute__((returns_twice)) returns_twice_test();
int aligned(int);
-int __attribute__((vec_type_hint(char, aligned(16) )) missing_rparen_1; // expected-error {{expected ')'}}
+int __attribute__((vec_type_hint(char, aligned(16) )) missing_rparen_1; // expected-error 2{{expected ')'}} expected-note {{to match}} expected-warning {{does not declare anything}}
int __attribute__((mode(x aligned(16) )) missing_rparen_2; // expected-error {{expected ')'}}
int __attribute__((format(printf, 0 aligned(16) )) missing_rparen_3; // expected-error {{expected ')'}}
Index: test/Parser/cxx-attributes.cpp
===================================================================
--- test/Parser/cxx-attributes.cpp (revision 193295)
+++ test/Parser/cxx-attributes.cpp (working copy)
@@ -16,4 +16,7 @@
const int A = 1;
typedef int __attribute__((__aligned__(A))) T1;
int check1[__alignof__(T1) == 1 ? 1 : -1];
+
+ typedef int __attribute__((aligned(int(1)))) T1;
+ typedef int __attribute__((aligned(int))) T2; // expected-error {{expected '(' for function-style cast}}
}
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h (revision 193289)
+++ include/clang/Parse/Parser.h (working copy)
@@ -1983,6 +1983,11 @@
ParsedAttributes &Attrs,
SourceLocation *EndLoc);
+ void ParseAttributeWithTypeArg(IdentifierInfo &AttrName,
+ SourceLocation AttrNameLoc,
+ ParsedAttributes &Attrs,
+ SourceLocation *EndLoc);
+
void ParseTypeofSpecifier(DeclSpec &DS);
SourceLocation ParseDecltypeSpecifier(DeclSpec &DS);
void AnnotateExistingDecltypeSpecifier(const DeclSpec &DS,
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td (revision 193289)
+++ include/clang/Basic/DiagnosticSemaKinds.td (working copy)
@@ -2390,6 +2390,8 @@
InGroup<IgnoredAttributes>;
def err_iboutletcollection_type : Error<
"invalid type %0 as argument of iboutletcollection attribute">;
+def err_iboutletcollection_builtintype : Error<
+ "type argument of iboutletcollection attribute cannot be a builtin type">;
def warn_iboutlet_object_type : Warning<
"%select{instance variable|property}2 with %0 attribute must "
"be an object type (invalid %1)">, InGroup<ObjCInvalidIBOutletProperty>;
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td (revision 193289)
+++ include/clang/Basic/DiagnosticParseKinds.td (working copy)
@@ -167,8 +167,6 @@
"expected member name or ';' after declaration specifiers">;
def err_function_declared_typedef : Error<
"function definition declared 'typedef'">;
-def err_iboutletcollection_builtintype : Error<
- "type argument of iboutletcollection attribute cannot be a builtin type">;
def err_iboutletcollection_with_protocol : Error<
"invalid argument of iboutletcollection attribute">;
def err_at_defs_cxx : Error<"@defs is not supported in Objective-C++">;
Index: include/clang/Sema/AttributeList.h
===================================================================
--- include/clang/Sema/AttributeList.h (revision 193289)
+++ include/clang/Sema/AttributeList.h (working copy)
@@ -450,7 +450,7 @@
}
const ParsedType &getTypeArg() const {
- assert(getKind() == AT_VecTypeHint && "Not a type attribute");
+ assert(HasParsedType && "Not a type attribute");
return getTypeBuffer();
}
Index: tools/libclang/CIndex.cpp
===================================================================
--- tools/libclang/CIndex.cpp (revision 193289)
+++ tools/libclang/CIndex.cpp (working copy)
@@ -532,8 +532,8 @@
if (Cursor.kind == CXCursor_IBOutletCollectionAttr) {
const IBOutletCollectionAttr *A =
cast<IBOutletCollectionAttr>(cxcursor::getCursorAttr(Cursor));
- if (const ObjCInterfaceType *InterT = A->getInterface()->getAs<ObjCInterfaceType>())
- return Visit(cxcursor::MakeCursorObjCClassRef(InterT->getInterface(),
+ if (const ObjCObjectType *ObjT = A->getInterface()->getAs<ObjCObjectType>())
+ return Visit(cxcursor::MakeCursorObjCClassRef(ObjT->getInterface(),
A->getInterfaceLoc(), TU));
}
Index: tools/libclang/IndexingContext.cpp
===================================================================
--- tools/libclang/IndexingContext.cpp (revision 193289)
+++ tools/libclang/IndexingContext.cpp (working copy)
@@ -99,8 +99,8 @@
IBInfo.IBCollInfo.objcClass = 0;
IBInfo.IBCollInfo.classCursor = clang_getNullCursor();
QualType Ty = IBAttr->getInterface();
- if (const ObjCInterfaceType *InterTy = Ty->getAs<ObjCInterfaceType>()) {
- if (const ObjCInterfaceDecl *InterD = InterTy->getInterface()) {
+ if (const ObjCObjectType *ObjectTy = Ty->getAs<ObjCObjectType>()) {
+ if (const ObjCInterfaceDecl *InterD = ObjectTy->getInterface()) {
IdxCtx.getEntityInfo(InterD, IBInfo.ClassInfo, SA);
IBInfo.IBCollInfo.objcClass = &IBInfo.ClassInfo;
IBInfo.IBCollInfo.classCursor = MakeCursorObjCClassRef(InterD,
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits