forked from OSchip/llvm-project
[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; static_cast<NSString**>(&x); // Casting as (__strong NSString**). This currently only works for C++ named casts, C casts to follow. llvm-svn: 134273
This commit is contained in:
parent
e9b5c85041
commit
7451d1cd00
|
@ -1347,6 +1347,10 @@ public:
|
|||
/// integer type.
|
||||
QualType getPromotedIntegerType(QualType PromotableType) const;
|
||||
|
||||
/// \brief Recurses in pointer/array types until it finds an objc retainable
|
||||
/// type and returns its ownership.
|
||||
Qualifiers::ObjCLifetime getInnerObjCOwnership(QualType T) const;
|
||||
|
||||
/// \brief Whether this is a promotable bitfield reference according
|
||||
/// to C99 6.3.1.1p2, bullet 2 (and GCC extensions).
|
||||
///
|
||||
|
|
|
@ -783,6 +783,7 @@ public:
|
|||
QualType BuildParenType(QualType T);
|
||||
|
||||
TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S);
|
||||
TypeSourceInfo *GetTypeForDeclaratorCast(Declarator &D, QualType FromTy);
|
||||
TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
|
||||
TypeSourceInfo *ReturnTypeInfo);
|
||||
/// \brief Package the given type and TSI into a ParsedType.
|
||||
|
@ -2825,7 +2826,7 @@ public:
|
|||
ExprResult ActOnCXXNamedCast(SourceLocation OpLoc,
|
||||
tok::TokenKind Kind,
|
||||
SourceLocation LAngleBracketLoc,
|
||||
ParsedType Ty,
|
||||
Declarator &D,
|
||||
SourceLocation RAngleBracketLoc,
|
||||
SourceLocation LParenLoc,
|
||||
Expr *E,
|
||||
|
|
|
@ -3512,6 +3512,25 @@ QualType ASTContext::getPromotedIntegerType(QualType Promotable) const {
|
|||
return (PromotableSize != IntSize) ? IntTy : UnsignedIntTy;
|
||||
}
|
||||
|
||||
/// \brief Recurses in pointer/array types until it finds an objc retainable
|
||||
/// type and returns its ownership.
|
||||
Qualifiers::ObjCLifetime ASTContext::getInnerObjCOwnership(QualType T) const {
|
||||
while (!T.isNull()) {
|
||||
if (T.getObjCLifetime() != Qualifiers::OCL_None)
|
||||
return T.getObjCLifetime();
|
||||
if (T->isArrayType())
|
||||
T = getBaseElementType(T);
|
||||
else if (const PointerType *PT = T->getAs<PointerType>())
|
||||
T = PT->getPointeeType();
|
||||
else if (const ReferenceType *RT = T->getAs<ReferenceType>())
|
||||
RT->getPointeeType();
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return Qualifiers::OCL_None;
|
||||
}
|
||||
|
||||
/// getIntegerTypeOrder - Returns the highest ranked integer type:
|
||||
/// C99 6.3.1.8p1. If LHS > RHS, return 1. If LHS == RHS, return 0. If
|
||||
/// LHS < RHS, return -1.
|
||||
|
|
|
@ -538,7 +538,14 @@ ExprResult Parser::ParseCXXCasts() {
|
|||
if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName))
|
||||
return ExprError();
|
||||
|
||||
TypeResult CastTy = ParseTypeName();
|
||||
// Parse the common declaration-specifiers piece.
|
||||
DeclSpec DS(AttrFactory);
|
||||
ParseSpecifierQualifierList(DS);
|
||||
|
||||
// Parse the abstract-declarator, if present.
|
||||
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
|
||||
ParseDeclarator(DeclaratorInfo);
|
||||
|
||||
SourceLocation RAngleBracketLoc = Tok.getLocation();
|
||||
|
||||
if (ExpectAndConsume(tok::greater, diag::err_expected_greater))
|
||||
|
@ -554,9 +561,9 @@ ExprResult Parser::ParseCXXCasts() {
|
|||
// Match the ')'.
|
||||
RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
||||
|
||||
if (!Result.isInvalid() && !CastTy.isInvalid())
|
||||
if (!Result.isInvalid() && !DeclaratorInfo.isInvalidType())
|
||||
Result = Actions.ActOnCXXNamedCast(OpLoc, Kind,
|
||||
LAngleBracketLoc, CastTy.get(),
|
||||
LAngleBracketLoc, DeclaratorInfo,
|
||||
RAngleBracketLoc,
|
||||
LParenLoc, Result.take(), RParenLoc);
|
||||
|
||||
|
|
|
@ -134,17 +134,23 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
|
|||
/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
|
||||
ExprResult
|
||||
Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
|
||||
SourceLocation LAngleBracketLoc, ParsedType Ty,
|
||||
SourceLocation LAngleBracketLoc, Declarator &D,
|
||||
SourceLocation RAngleBracketLoc,
|
||||
SourceLocation LParenLoc, Expr *E,
|
||||
SourceLocation RParenLoc) {
|
||||
|
||||
TypeSourceInfo *DestTInfo;
|
||||
QualType DestType = GetTypeFromParser(Ty, &DestTInfo);
|
||||
if (!DestTInfo)
|
||||
DestTInfo = Context.getTrivialTypeSourceInfo(DestType, SourceLocation());
|
||||
|
||||
return BuildCXXNamedCast(OpLoc, Kind, DestTInfo, move(E),
|
||||
assert(!D.isInvalidType());
|
||||
|
||||
TypeSourceInfo *TInfo = GetTypeForDeclaratorCast(D, E->getType());
|
||||
if (D.isInvalidType())
|
||||
return ExprError();
|
||||
|
||||
if (getLangOptions().CPlusPlus) {
|
||||
// Check that there are no default arguments (C++ only).
|
||||
CheckExtraCXXDefaultArguments(D);
|
||||
}
|
||||
|
||||
return BuildCXXNamedCast(OpLoc, Kind, TInfo, move(E),
|
||||
SourceRange(LAngleBracketLoc, RAngleBracketLoc),
|
||||
SourceRange(LParenLoc, RParenLoc));
|
||||
}
|
||||
|
|
|
@ -2534,6 +2534,117 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {
|
|||
return GetFullTypeForDeclarator(state, T, ReturnTypeInfo);
|
||||
}
|
||||
|
||||
static void transferARCOwnershipToDeclSpec(Sema &S,
|
||||
QualType &declSpecTy,
|
||||
Qualifiers::ObjCLifetime ownership) {
|
||||
if (declSpecTy->isObjCRetainableType() &&
|
||||
declSpecTy.getObjCLifetime() == Qualifiers::OCL_None) {
|
||||
Qualifiers qs;
|
||||
qs.addObjCLifetime(ownership);
|
||||
declSpecTy = S.Context.getQualifiedType(declSpecTy, qs);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state,
|
||||
Qualifiers::ObjCLifetime ownership,
|
||||
unsigned chunkIndex) {
|
||||
Sema &S = state.getSema();
|
||||
Declarator &D = state.getDeclarator();
|
||||
|
||||
// Look for an explicit lifetime attribute.
|
||||
DeclaratorChunk &chunk = D.getTypeObject(chunkIndex);
|
||||
for (const AttributeList *attr = chunk.getAttrs(); attr;
|
||||
attr = attr->getNext())
|
||||
if (attr->getKind() == AttributeList::AT_objc_ownership)
|
||||
return;
|
||||
|
||||
const char *attrStr = 0;
|
||||
switch (ownership) {
|
||||
case Qualifiers::OCL_None: llvm_unreachable("no ownership!"); break;
|
||||
case Qualifiers::OCL_ExplicitNone: attrStr = "none"; break;
|
||||
case Qualifiers::OCL_Strong: attrStr = "strong"; break;
|
||||
case Qualifiers::OCL_Weak: attrStr = "weak"; break;
|
||||
case Qualifiers::OCL_Autoreleasing: attrStr = "autoreleasing"; break;
|
||||
}
|
||||
if (!attrStr)
|
||||
return;
|
||||
|
||||
// If there wasn't one, add one (with an invalid source location
|
||||
// so that we don't make an AttributedType for it).
|
||||
AttributeList *attr = D.getAttributePool()
|
||||
.create(&S.Context.Idents.get("objc_ownership"), SourceLocation(),
|
||||
/*scope*/ 0, SourceLocation(),
|
||||
&S.Context.Idents.get(attrStr), SourceLocation(),
|
||||
/*args*/ 0, 0,
|
||||
/*declspec*/ false, /*C++0x*/ false);
|
||||
spliceAttrIntoList(*attr, chunk.getAttrListRef());
|
||||
|
||||
// TODO: mark whether we did this inference?
|
||||
}
|
||||
|
||||
static void transferARCOwnership(TypeProcessingState &state,
|
||||
QualType &declSpecTy,
|
||||
Qualifiers::ObjCLifetime ownership) {
|
||||
Sema &S = state.getSema();
|
||||
Declarator &D = state.getDeclarator();
|
||||
|
||||
int inner = -1;
|
||||
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
|
||||
DeclaratorChunk &chunk = D.getTypeObject(i);
|
||||
switch (chunk.Kind) {
|
||||
case DeclaratorChunk::Paren:
|
||||
// Ignore parens.
|
||||
break;
|
||||
|
||||
case DeclaratorChunk::Array:
|
||||
case DeclaratorChunk::Reference:
|
||||
case DeclaratorChunk::Pointer:
|
||||
inner = i;
|
||||
break;
|
||||
|
||||
case DeclaratorChunk::BlockPointer:
|
||||
return transferARCOwnershipToDeclaratorChunk(state, ownership, i);
|
||||
|
||||
case DeclaratorChunk::Function:
|
||||
case DeclaratorChunk::MemberPointer:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (inner == -1)
|
||||
return transferARCOwnershipToDeclSpec(S, declSpecTy, ownership);
|
||||
|
||||
DeclaratorChunk &chunk = D.getTypeObject(inner);
|
||||
if (chunk.Kind == DeclaratorChunk::Pointer) {
|
||||
if (declSpecTy->isObjCRetainableType())
|
||||
return transferARCOwnershipToDeclSpec(S, declSpecTy, ownership);
|
||||
if (declSpecTy->isObjCObjectType())
|
||||
return transferARCOwnershipToDeclaratorChunk(state, ownership, inner);
|
||||
} else {
|
||||
assert(chunk.Kind == DeclaratorChunk::Array ||
|
||||
chunk.Kind == DeclaratorChunk::Reference);
|
||||
return transferARCOwnershipToDeclSpec(S, declSpecTy, ownership);
|
||||
}
|
||||
}
|
||||
|
||||
TypeSourceInfo *Sema::GetTypeForDeclaratorCast(Declarator &D, QualType FromTy) {
|
||||
TypeProcessingState state(*this, D);
|
||||
|
||||
TypeSourceInfo *ReturnTypeInfo = 0;
|
||||
QualType declSpecTy = GetDeclSpecTypeForDeclarator(state, ReturnTypeInfo);
|
||||
if (declSpecTy.isNull())
|
||||
return Context.getNullTypeSourceInfo();
|
||||
|
||||
if (getLangOptions().ObjCAutoRefCount) {
|
||||
Qualifiers::ObjCLifetime ownership = Context.getInnerObjCOwnership(FromTy);
|
||||
if (ownership != Qualifiers::OCL_None)
|
||||
transferARCOwnership(state, declSpecTy, ownership);
|
||||
}
|
||||
|
||||
return GetFullTypeForDeclarator(state, declSpecTy, ReturnTypeInfo);
|
||||
}
|
||||
|
||||
/// Map an AttributedType::Kind to an AttributeList::Kind.
|
||||
static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) {
|
||||
switch (kind) {
|
||||
|
|
|
@ -46,7 +46,7 @@ void j() {
|
|||
U<auto> v; // expected-error{{'auto' not allowed in template argument}}
|
||||
|
||||
int n;
|
||||
(void)dynamic_cast<auto&>(S()); // expected-error{{'auto' not allowed here}}
|
||||
(void)dynamic_cast<auto&>(n); // expected-error{{'auto' not allowed here}}
|
||||
(void)static_cast<auto*>(&n); // expected-error{{'auto' not allowed here}}
|
||||
(void)reinterpret_cast<auto*>(&n); // expected-error{{'auto' not allowed here}}
|
||||
(void)const_cast<auto>(n); // expected-error{{'auto' not allowed here}}
|
||||
|
|
|
@ -42,8 +42,7 @@ void static_casts(id arg) {
|
|||
(void)static_cast<int*>(arg); // expected-error {{cannot cast from type 'id' to pointer type 'int *'}}
|
||||
(void)static_cast<id>(arg);
|
||||
(void)static_cast<__autoreleasing id*>(arg); // expected-error{{cannot cast from type 'id' to pointer type '__autoreleasing id *'}}
|
||||
(void)static_cast<id*>(arg); // expected-error {{cannot cast from type 'id' to pointer type '__autoreleasing id *'}} \
|
||||
// expected-error{{pointer to non-const type 'id' with no explicit ownership}}
|
||||
(void)static_cast<id*>(arg); // expected-error {{cannot cast from type 'id' to pointer type '__strong id *'}}
|
||||
|
||||
(void)static_cast<__autoreleasing id**>(voidp_val);
|
||||
(void)static_cast<void*>(voidp_val);
|
||||
|
@ -196,3 +195,24 @@ void from_void(void *vp) {
|
|||
aip = vp; // expected-error{{assigning to '__autoreleasing id *' from incompatible type 'void *'}}
|
||||
uip = vp; // expected-error{{assigning to '__unsafe_unretained id *' from incompatible type 'void *'}}
|
||||
}
|
||||
|
||||
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 **sip2 = static_cast<NSString **>(static_cast<__strong id *>(vp));
|
||||
__weak NSString **wip2 = static_cast<NSString **>(static_cast<__weak id *>(vp));
|
||||
__autoreleasing id *aip2 = static_cast<id *>(static_cast<__autoreleasing id *>(vp));
|
||||
__unsafe_unretained id *uip2 = static_cast<id *>(static_cast<__unsafe_unretained id *>(vp));
|
||||
__strong id *sip3 = reinterpret_cast<id *>(reinterpret_cast<__strong id *>(vp));
|
||||
__weak id *wip3 = reinterpret_cast<id *>(reinterpret_cast<__weak id *>(vp));
|
||||
__autoreleasing id *aip3 = reinterpret_cast<id *>(reinterpret_cast<__autoreleasing id *>(vp));
|
||||
__unsafe_unretained id *uip3 = reinterpret_cast<id *>(reinterpret_cast<__unsafe_unretained id *>(vp));
|
||||
|
||||
Block_strong blk_strong1;
|
||||
Block_strong blk_strong2 = static_cast<Block>(blk_strong1);
|
||||
Block_autoreleasing *blk_auto = static_cast<Block*>(pblk);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue