diff options
-rw-r--r-- | clang/include/clang/Parse/Parser.h | 14 | ||||
-rw-r--r-- | clang/include/clang/Sema/DeclSpec.h | 17 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Parse/ParseObjc.cpp | 82 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 14 | ||||
-rw-r--r-- | clang/test/CodeGenObjC/arc.m | 24 |
7 files changed, 122 insertions, 33 deletions
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 93812c38634..e8494767b58 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1138,13 +1138,8 @@ private: bool isTokIdentifier_in() const; - /// \brief The context in which we are parsing an Objective-C type name. - enum ObjCTypeNameContext { - OTN_ResultType, - OTN_ParameterType - }; - - ParsedType ParseObjCTypeName(ObjCDeclSpec &DS, ObjCTypeNameContext Context); + ParsedType ParseObjCTypeName(ObjCDeclSpec &DS, Declarator::TheContext Ctx, + ParsedAttributes *ParamAttrs); void ParseObjCMethodRequirement(); Decl *ParseObjCMethodPrototype( tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword, @@ -1508,8 +1503,8 @@ private: void ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS = AS_none); - void ParseObjCTypeQualifierList(ObjCDeclSpec &DS, - ObjCTypeNameContext Context); + void ParseObjCTypeQualifierList(ObjCDeclSpec &DS, + Declarator::TheContext Context); void ParseEnumSpecifier(SourceLocation TagLoc, DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), @@ -1684,7 +1679,6 @@ private: TypeResult ParseTypeName(SourceRange *Range = 0, Declarator::TheContext Context = Declarator::TypeNameContext, - ObjCDeclSpec *objcQuals = 0, AccessSpecifier AS = AS_none, Decl **OwnedType = 0); void ParseBlockId(); diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 0c357f1e66f..d06c1ed70d0 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -736,6 +736,7 @@ public: const IdentifierInfo *getSetterName() const { return SetterName; } IdentifierInfo *getSetterName() { return SetterName; } void setSetterName(IdentifierInfo *name) { SetterName = name; } + private: // FIXME: These two are unrelated and mutially exclusive. So perhaps // we can put them in a union to reflect their mutual exclusiveness @@ -1368,7 +1369,8 @@ public: enum TheContext { FileContext, // File scope declaration. PrototypeContext, // Within a function prototype. - ObjCPrototypeContext,// Within a method prototype. + ObjCResultContext, // An ObjC method result type. + ObjCParameterContext,// An ObjC method parameter type. KNRTypeListContext, // K&R type definition list for formals. TypeNameContext, // Abstract declarator for types. MemberContext, // Struct/Union field. @@ -1466,7 +1468,9 @@ public: TheContext getContext() const { return Context; } bool isPrototypeContext() const { - return (Context == PrototypeContext || Context == ObjCPrototypeContext); + return (Context == PrototypeContext || + Context == ObjCParameterContext || + Context == ObjCResultContext); } /// getSourceRange - Get the source range that spans this declarator. @@ -1526,7 +1530,8 @@ public: case AliasDeclContext: case AliasTemplateContext: case PrototypeContext: - case ObjCPrototypeContext: + case ObjCParameterContext: + case ObjCResultContext: case TemplateParamContext: case CXXNewContext: case CXXCatchContext: @@ -1559,7 +1564,8 @@ public: case CXXNewContext: case AliasDeclContext: case AliasTemplateContext: - case ObjCPrototypeContext: + case ObjCParameterContext: + case ObjCResultContext: case BlockLiteralContext: case TemplateTypeArgContext: return false; @@ -1582,7 +1588,8 @@ public: case MemberContext: case ConditionContext: case PrototypeContext: - case ObjCPrototypeContext: + case ObjCParameterContext: + case ObjCResultContext: case TemplateParamContext: case CXXCatchContext: case ObjCCatchContext: diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index e9d3185b9a8..0e4fee3086d 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -33,12 +33,10 @@ using namespace clang; /// Called type-id in C++. TypeResult Parser::ParseTypeName(SourceRange *Range, Declarator::TheContext Context, - ObjCDeclSpec *objcQuals, AccessSpecifier AS, Decl **OwnedType) { // Parse the common declaration-specifiers piece. DeclSpec DS(AttrFactory); - DS.setObjCQualifiers(objcQuals); ParseSpecifierQualifierList(DS, AS); if (OwnedType) *OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : 0; diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 2fd5c0059dc..5d7a7729f18 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -519,7 +519,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, TypeAlias = ParseTypeName(0, TemplateInfo.Kind ? Declarator::AliasTemplateContext : - Declarator::AliasDeclContext, 0, AS, OwnedType); + Declarator::AliasDeclContext, AS, OwnedType); } else // Parse (optional) attributes (most likely GNU strong-using extension). MaybeParseGNUAttributes(attrs); diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 1d600626026..6ebe3b2df1e 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -742,11 +742,14 @@ bool Parser::isTokIdentifier_in() const { /// objc-type-qualifiers objc-type-qualifier /// void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS, - ObjCTypeNameContext Context) { + Declarator::TheContext Context) { + assert(Context == Declarator::ObjCParameterContext || + Context == Declarator::ObjCResultContext); + while (1) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCPassingType(getCurScope(), DS, - Context == OTN_ParameterType); + Context == Declarator::ObjCParameterContext); return cutOffParsing(); } @@ -779,12 +782,51 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS, } } +/// Take all the decl attributes out of the given list and add +/// them to the given attribute set. +static void takeDeclAttributes(ParsedAttributes &attrs, + AttributeList *list) { + while (list) { + AttributeList *cur = list; + list = cur->getNext(); + + if (!cur->isUsedAsTypeAttr()) { + // Clear out the next pointer. We're really completely + // destroying the internal invariants of the declarator here, + // but it doesn't matter because we're done with it. + cur->setNext(0); + attrs.add(cur); + } + } +} + +/// takeDeclAttributes - Take all the decl attributes from the given +/// declarator and add them to the given list. +static void takeDeclAttributes(ParsedAttributes &attrs, + Declarator &D) { + // First, take ownership of all attributes. + attrs.getPool().takeAllFrom(D.getAttributePool()); + attrs.getPool().takeAllFrom(D.getDeclSpec().getAttributePool()); + + // Now actually move the attributes over. + takeDeclAttributes(attrs, D.getDeclSpec().getAttributes().getList()); + takeDeclAttributes(attrs, D.getAttributes()); + for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) + takeDeclAttributes(attrs, + const_cast<AttributeList*>(D.getTypeObject(i).getAttrs())); +} + /// objc-type-name: /// '(' objc-type-qualifiers[opt] type-name ')' /// '(' objc-type-qualifiers[opt] ')' /// ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS, - ObjCTypeNameContext Context) { + Declarator::TheContext context, + ParsedAttributes *paramAttrs) { + assert(context == Declarator::ObjCParameterContext || + context == Declarator::ObjCResultContext); + assert((paramAttrs != 0) == (context == Declarator::ObjCParameterContext)); + assert(Tok.is(tok::l_paren) && "expected ("); SourceLocation LParenLoc = ConsumeParen(); @@ -792,15 +834,30 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS, ObjCDeclContextSwitch ObjCDC(*this); // Parse type qualifiers, in, inout, etc. - ParseObjCTypeQualifierList(DS, Context); + ParseObjCTypeQualifierList(DS, context); ParsedType Ty; if (isTypeSpecifierQualifier()) { - TypeResult TypeSpec = - ParseTypeName(0, Declarator::ObjCPrototypeContext, &DS); - if (!TypeSpec.isInvalid()) - Ty = TypeSpec.get(); - } else if (Context == OTN_ResultType && Tok.is(tok::identifier)) { + // Parse an abstract declarator. + DeclSpec declSpec(AttrFactory); + declSpec.setObjCQualifiers(&DS); + ParseSpecifierQualifierList(declSpec); + Declarator declarator(declSpec, context); + ParseDeclarator(declarator); + + // If that's not invalid, extract a type. + if (!declarator.isInvalidType()) { + TypeResult type = Actions.ActOnTypeName(getCurScope(), declarator); + if (!type.isInvalid()) + Ty = type.get(); + + // If we're parsing a parameter, steal all the decl attributes + // and add them to the decl spec. + if (context == Declarator::ObjCParameterContext) + takeDeclAttributes(*paramAttrs, declarator); + } + } else if (context == Declarator::ObjCResultContext && + Tok.is(tok::identifier)) { if (!Ident_instancetype) Ident_instancetype = PP.getIdentifierInfo("instancetype"); @@ -869,7 +926,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, ParsedType ReturnType; ObjCDeclSpec DSRet; if (Tok.is(tok::l_paren)) - ReturnType = ParseObjCTypeName(DSRet, OTN_ResultType); + ReturnType = ParseObjCTypeName(DSRet, Declarator::ObjCResultContext, 0); // If attributes exist before the method, parse them. ParsedAttributes methodAttrs(AttrFactory); @@ -934,9 +991,12 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, ArgInfo.Type = ParsedType(); if (Tok.is(tok::l_paren)) // Parse the argument type if present. - ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec, OTN_ParameterType); + ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec, + Declarator::ObjCParameterContext, + ¶mAttrs); // If attributes exist before the argument name, parse them. + // Regardless, collect all the attributes we've parsed so far. ArgInfo.ArgAttrs = 0; if (getLang().ObjC2) { MaybeParseGNUAttributes(paramAttrs); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 9707804cf02..4a865bf2358 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1752,7 +1752,8 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, case Declarator::KNRTypeListContext: llvm_unreachable("K&R type lists aren't allowed in C++"); break; - case Declarator::ObjCPrototypeContext: + case Declarator::ObjCParameterContext: + case Declarator::ObjCResultContext: case Declarator::PrototypeContext: Error = 0; // Function prototype break; @@ -1861,7 +1862,8 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, << SemaRef.Context.getTypeDeclType(OwnedTagDecl); break; case Declarator::PrototypeContext: - case Declarator::ObjCPrototypeContext: + case Declarator::ObjCParameterContext: + case Declarator::ObjCResultContext: case Declarator::KNRTypeListContext: // C++ [dcl.fct]p6: // Types shall not be defined in return or parameter types. @@ -2482,7 +2484,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case Declarator::FileContext: case Declarator::KNRTypeListContext: - case Declarator::ObjCPrototypeContext: // FIXME: special diagnostic here? + case Declarator::ObjCParameterContext: // FIXME: special diagnostic here? + case Declarator::ObjCResultContext: // FIXME: special diagnostic here? case Declarator::TypeNameContext: case Declarator::CXXNewContext: case Declarator::AliasDeclContext: @@ -3065,7 +3068,10 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { return true; // Make sure there are no unused decl attributes on the declarator. - checkUnusedDeclAttributes(D); + // We don't want to do this for ObjC parameters because we're going + // to apply them to the actual parameter declaration. + if (D.getContext() != Declarator::ObjCParameterContext) + checkUnusedDeclAttributes(D); if (getLangOptions().CPlusPlus) { // Check that there are no default arguments (C++ only). diff --git a/clang/test/CodeGenObjC/arc.m b/clang/test/CodeGenObjC/arc.m index ebbc3473166..7889bcf42c2 100644 --- a/clang/test/CodeGenObjC/arc.m +++ b/clang/test/CodeGenObjC/arc.m @@ -1912,3 +1912,27 @@ void test64b(void) { // CHECK: define internal void @"\01-[Test65 setNblock:]"( // CHECK: call void @objc_setProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i8* {{%.*}}, i1 zeroext false, i1 zeroext true) @end + +// Verify that we successfully parse and preserve this attribute in +// this position. +@interface Test66 +- (void) consume: (id __attribute__((ns_consumed))) ptr; +@end +void test66(void) { + extern Test66 *test66_receiver(void); + extern id test66_arg(void); + [test66_receiver() consume: test66_arg()]; +} +// CHECK: define void @test66() +// CHECK: [[T0:%.*]] = call [[TEST66:%.*]]* @test66_receiver() +// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST66]]* [[T0]] to i8* +// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]]) +// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST66]]* +// CHECK-NEXT: [[T4:%.*]] = call i8* @test66_arg() +// CHECK-NEXT: [[T5:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T4]]) +// CHECK-NEXT: [[T6:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES +// CHECK-NEXT: [[T7:%.*]] = bitcast [[TEST66]]* [[T3]] to i8* +// CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8*)*)(i8* [[T7]], i8* [[T6]], i8* [[T5]]) +// CHECK-NEXT: [[T8:%.*]] = bitcast [[TEST66]]* [[T3]] to i8* +// CHECK-NEXT: call void @objc_release(i8* [[T8]]) +// CHECK-NEXT: ret void |