From: Argyrios Kyrtzidis Date: Fri, 1 Jul 2011 22:22:59 +0000 (+0000) Subject: [ARC] When casting from a pointer to an objective-c object with known ownership,... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0a85183be6930571f3af8e5a976d24c3f95e5b25;p=clang [ARC] When casting from a pointer to an objective-c object with known ownership, if the cast type has no ownership specified, implicitly "transfer" the ownership of the cast'ed type to the cast type: id x; (NSString**)&x; // Casting as (__strong NSString**). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@134275 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 626ad5316d..abd1ff2170 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1135,10 +1135,10 @@ private: ExprResult ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, bool &NotCastExpr, - ParsedType TypeOfCast); + bool isTypeCast); ExprResult ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand = false, - ParsedType TypeOfCast = ParsedType()); + bool isTypeCast = false); /// Returns true if the next token would start a postfix-expression /// suffix. @@ -1179,7 +1179,7 @@ private: }; ExprResult ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, - ParsedType TypeOfCast, + bool isTypeCast, ParsedType &CastTy, SourceLocation &RParenLoc); diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index bcac0342ce..69686b34fa 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2376,8 +2376,8 @@ public: MultiExprArg ExecConfig, SourceLocation GGGLoc); ExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc, - ParsedType Ty, SourceLocation RParenLoc, - Expr *Op); + Declarator &D, ParsedType &Ty, + SourceLocation RParenLoc, Expr *Op); ExprResult BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty, SourceLocation RParenLoc, diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index bd723f0325..5e8bb53b2d 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -220,7 +220,7 @@ ExprResult Parser::ParseAssignmentExpression() { if (Tok.is(tok::kw_throw)) return ParseThrowExpression(); - ExprResult LHS = ParseCastExpression(false, false, ParsedType()); + ExprResult LHS = ParseCastExpression(/*isUnaryExpression=*/false); return ParseRHSOfBinaryExpression(move(LHS), prec::Assignment); } @@ -415,12 +415,12 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { /// ExprResult Parser::ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, - ParsedType TypeOfCast) { + bool isTypeCast) { bool NotCastExpr; ExprResult Res = ParseCastExpression(isUnaryExpression, isAddressOfOperand, NotCastExpr, - TypeOfCast); + isTypeCast); if (NotCastExpr) Diag(Tok, diag::err_expected_expression); return move(Res); @@ -589,7 +589,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, ExprResult Parser::ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, bool &NotCastExpr, - ParsedType TypeOfCast) { + bool isTypeCast) { ExprResult Res; tok::TokenKind SavedKind = Tok.getKind(); NotCastExpr = false; @@ -620,7 +620,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, ColonProtectionRAIIObject X(*this, false); Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/, - TypeOfCast, CastTy, RParenLoc); + isTypeCast, CastTy, RParenLoc); } switch (ParenExprType) { @@ -952,7 +952,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, return ExprError(); if (!Tok.is(tok::annot_cxxscope)) return ParseCastExpression(isUnaryExpression, isAddressOfOperand, - NotCastExpr, TypeOfCast); + NotCastExpr, isTypeCast); Token Next = NextToken(); if (Next.is(tok::annot_template_id)) { @@ -965,7 +965,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false); AnnotateTemplateIdTokenAsType(); return ParseCastExpression(isUnaryExpression, isAddressOfOperand, - NotCastExpr, TypeOfCast); + NotCastExpr, isTypeCast); } } @@ -982,7 +982,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // expression. AnnotateTemplateIdTokenAsType(); return ParseCastExpression(isUnaryExpression, isAddressOfOperand, - NotCastExpr, TypeOfCast); + NotCastExpr, isTypeCast); } // Fall through to treat the template-id as an id-expression. @@ -1105,7 +1105,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); ConsumeCodeCompletionToken(); return ParseCastExpression(isUnaryExpression, isAddressOfOperand, - NotCastExpr, TypeOfCast); + NotCastExpr, isTypeCast); case tok::l_square: // These can be followed by postfix-expr pieces. if (getLang().ObjC1) @@ -1422,7 +1422,7 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/, - ParsedType(), CastTy, RParenLoc); + false, CastTy, RParenLoc); CastRange = SourceRange(LParenLoc, RParenLoc); // If ParseParenExpression parsed a '(typename)' sequence only, then this is @@ -1746,7 +1746,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { /// (__bridge_retained type-name) cast-expression ExprResult Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, - ParsedType TypeOfCast, ParsedType &CastTy, + bool isTypeCast, ParsedType &CastTy, SourceLocation &RParenLoc) { assert(Tok.is(tok::l_paren) && "Not a paren expr!"); GreaterThanIsOperatorScope G(GreaterThanIsOperator, true); @@ -1804,7 +1804,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, TypeResult Ty = ParseTypeName(); SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, OpenLoc); - ExprResult SubExpr = ParseCastExpression(false, false, ParsedType()); + ExprResult SubExpr = ParseCastExpression(/*isUnaryExpression=*/false); if (Ty.isInvalid() || SubExpr.isInvalid()) return ExprError(); @@ -1826,20 +1826,23 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, return ParseCXXAmbiguousParenExpression(ExprType, CastTy, OpenLoc, RParenLoc); - TypeResult Ty; - - { - InMessageExpressionRAIIObject InMessage(*this, false); - Ty = ParseTypeName(); - } + // Parse the type declarator. + DeclSpec DS(AttrFactory); + ParseSpecifierQualifierList(DS); + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + ParseDeclarator(DeclaratorInfo); // If our type is followed by an identifier and either ':' or ']', then // this is probably an Objective-C message send where the leading '[' is // missing. Recover as if that were the case. - if (!Ty.isInvalid() && Tok.is(tok::identifier) && !InMessageExpression && - getLang().ObjC1 && !Ty.get().get().isNull() && - (NextToken().is(tok::colon) || NextToken().is(tok::r_square)) && - Ty.get().get()->isObjCObjectOrInterfaceType()) { + if (!DeclaratorInfo.isInvalidType() && Tok.is(tok::identifier) && + !InMessageExpression && getLang().ObjC1 && + (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) { + TypeResult Ty; + { + InMessageExpressionRAIIObject InMessage(*this, false); + Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); + } Result = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(), Ty.get(), 0); @@ -1852,21 +1855,31 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, if (Tok.is(tok::l_brace)) { ExprType = CompoundLiteral; + TypeResult Ty; + { + InMessageExpressionRAIIObject InMessage(*this, false); + Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); + } return ParseCompoundLiteralExpression(Ty.get(), OpenLoc, RParenLoc); } if (ExprType == CastExpr) { // We parsed '(' type-name ')' and the thing after it wasn't a '{'. - if (Ty.isInvalid()) + if (DeclaratorInfo.isInvalidType()) return ExprError(); - CastTy = Ty.get(); - // Note that this doesn't parse the subsequent cast-expression, it just // returns the parsed type to the callee. - if (stopIfCastExpr) + if (stopIfCastExpr) { + TypeResult Ty; + { + InMessageExpressionRAIIObject InMessage(*this, false); + Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); + } + CastTy = Ty.get(); return ExprResult(); + } // Reject the cast of super idiom in ObjC. if (Tok.is(tok::identifier) && getLang().ObjC1 && @@ -1880,17 +1893,21 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, // Parse the cast-expression that follows it next. // TODO: For cast expression with CastTy. - Result = ParseCastExpression(false, false, CastTy); - if (!Result.isInvalid()) - Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc, CastTy, + Result = ParseCastExpression(/*isUnaryExpression=*/false, + /*isAddressOfOperand=*/false, + /*isTypeCast=*/true); + if (!Result.isInvalid()) { + Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc, + DeclaratorInfo, CastTy, RParenLoc, Result.take()); + } return move(Result); } Diag(Tok, diag::err_expected_lbrace_in_compound_literal); return ExprError(); } - } else if (TypeOfCast) { + } else if (isTypeCast) { // Parse the expression-list. InMessageExpressionRAIIObject InMessage(*this, false); diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 632499295f..6822681c7a 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -2200,7 +2200,8 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, Result = ParseCastExpression(false/*isUnaryExpression*/, false/*isAddressofOperand*/, NotCastExpr, - ParsedType()/*TypeOfCast*/); + // type-id has priority. + true/*isTypeCast*/); } // If we parsed a cast-expression, it's really a type-id, otherwise it's @@ -2219,7 +2220,11 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, ConsumeAnyToken(); if (ParseAs >= CompoundLiteral) { - TypeResult Ty = ParseTypeName(); + // Parse the type declarator. + DeclSpec DS(AttrFactory); + ParseSpecifierQualifierList(DS); + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + ParseDeclarator(DeclaratorInfo); // Match the ')'. if (Tok.is(tok::r_paren)) @@ -2229,21 +2234,21 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, if (ParseAs == CompoundLiteral) { ExprType = CompoundLiteral; + TypeResult Ty = ParseTypeName(); return ParseCompoundLiteralExpression(Ty.get(), LParenLoc, RParenLoc); } // We parsed '(' type-id ')' and the thing after it wasn't a '{'. assert(ParseAs == CastExpr); - if (Ty.isInvalid()) + if (DeclaratorInfo.isInvalidType()) return ExprError(); - CastTy = Ty.get(); - // Result is what ParseCastExpression returned earlier. if (!Result.isInvalid()) - Result = Actions.ActOnCastExpr(getCurScope(), LParenLoc, CastTy, RParenLoc, - Result.take()); + Result = Actions.ActOnCastExpr(getCurScope(), LParenLoc, + DeclaratorInfo, CastTy, + RParenLoc, Result.take()); return move(Result); } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index af0a3db688..68b767b474 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -4138,15 +4138,23 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, } ExprResult -Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, ParsedType Ty, +Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, + Declarator &D, ParsedType &Ty, SourceLocation RParenLoc, Expr *castExpr) { - assert((Ty != 0) && (castExpr != 0) && + assert(!D.isInvalidType() && (castExpr != 0) && "ActOnCastExpr(): missing type or expr"); - TypeSourceInfo *castTInfo; - QualType castType = GetTypeFromParser(Ty, &castTInfo); - if (!castTInfo) - castTInfo = Context.getTrivialTypeSourceInfo(castType); + TypeSourceInfo *castTInfo = GetTypeForDeclaratorCast(D, castExpr->getType()); + if (D.isInvalidType()) + return ExprError(); + + if (getLangOptions().CPlusPlus) { + // Check that there are no default arguments (C++ only). + CheckExtraCXXDefaultArguments(D); + } + + QualType castType = castTInfo->getType(); + Ty = CreateParsedType(castType, castTInfo); bool isVectorLiteral = false; diff --git a/test/ARCMT/checking.m b/test/ARCMT/checking.m index 08277c8a56..ed1592416b 100644 --- a/test/ARCMT/checking.m +++ b/test/ARCMT/checking.m @@ -100,7 +100,7 @@ void * cvt(id arg) (void)(int*)arg; // expected-error {{disallowed}} (void)(id)arg; (void)(__autoreleasing id*)arg; // expected-error {{disallowed}} - (void)(id*)arg; // expected-error {{pointer to non-const type 'id' with no explicit ownership}} expected-error {{disallowed}} + (void)(id*)arg; // expected-error {{disallowed}} (void)(__autoreleasing id**)voidp_val; (void)(void*)voidp_val; diff --git a/test/SemaObjC/arc-type-conversion.m b/test/SemaObjC/arc-type-conversion.m index 1c38597865..bb5686b691 100644 --- a/test/SemaObjC/arc-type-conversion.m +++ b/test/SemaObjC/arc-type-conversion.m @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-nonfragile-abi -verify %s +// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-nonfragile-abi -verify -fblocks %s void * cvt(id arg) { @@ -6,7 +6,7 @@ void * cvt(id arg) (void)(int*)arg; // expected-error {{cast of an Objective-C pointer to 'int *' is disallowed with ARC}} (void)(id)arg; (void)(__autoreleasing id*)arg; // expected-error {{cast of an Objective-C pointer to '__autoreleasing id *' is disallowed with ARC}} - (void)(id*)arg; // expected-error {{pointer to non-const type 'id' with no explicit ownership}} expected-error {{cast of an Objective-C pointer to '__autoreleasing id *' is disallowed with ARC}} + (void)(id*)arg; // expected-error {{cast of an Objective-C pointer to '__strong id *' is disallowed with ARC}} (void)(__autoreleasing id**)voidp_val; (void)(void*)voidp_val; @@ -53,3 +53,25 @@ void from_void(void *vp) { aip = vp; // expected-error{{implicit conversion of a non-Objective-C pointer type 'void *' to '__autoreleasing id *' is disallowed with ARC}} uip = vp; // expected-error{{implicit conversion of a non-Objective-C pointer type 'void *' to '__unsafe_unretained id *' is disallowed with ARC}} } + +typedef void (^Block)(); +typedef void (^Block_strong)() __strong; +typedef void (^Block_autoreleasing)() __autoreleasing; + +@class NSString; + +void ownership_transfer_in_cast(void *vp, Block *pblk) { + __strong NSString **sip = (NSString**)(__strong id *)vp; + __weak NSString **wip = (NSString**)(__weak id *)vp; + __autoreleasing id *aip = (id*)(__autoreleasing id *)vp; + __unsafe_unretained id *uip = (id*)(__unsafe_unretained id *)vp; + + __strong id **sipp = (id**)(__strong id **)vp; + __weak id **wipp = (id**)(__weak id **)vp; + __autoreleasing id **aipp = (id**)(__autoreleasing id **)vp; + __unsafe_unretained id **uipp = (id**)(__unsafe_unretained id **)vp; + + Block_strong blk_strong1; + Block_strong blk_strong2 = (Block)blk_strong1; + Block_autoreleasing *blk_auto = (Block*)pblk; +} diff --git a/test/SemaObjCXX/arc-type-conversion.mm b/test/SemaObjCXX/arc-type-conversion.mm index 7c6beaf1ad..7e2700ec6e 100644 --- a/test/SemaObjCXX/arc-type-conversion.mm +++ b/test/SemaObjCXX/arc-type-conversion.mm @@ -7,8 +7,7 @@ void * cvt(id arg) // expected-note{{candidate function not viable: cannot conve (void)(int*)arg; // expected-error {{cast of an Objective-C pointer to 'int *' is disallowed with ARC}} (void)(id)arg; (void)(__autoreleasing id*)arg; // expected-error{{C-style cast from 'id' to '__autoreleasing id *' casts away qualifiers}} - (void)(id*)arg; // expected-error {{pointer to non-const type 'id' with no explicit ownership}} \ - // expected-error{{C-style cast from 'id' to '__autoreleasing id *' casts away qualifiers}} + (void)(id*)arg; // expected-error{{C-style cast from 'id' to '__strong id *' casts away qualifiers}} (void)(__autoreleasing id**)voidp_val; (void)(void*)voidp_val;