Automatic Reference Counting.

Language-design credit goes to a lot of people, but I particularly want
to single out Blaine Garst and Patrick Beard for their contributions.

Compiler implementation credit goes to Argyrios, Doug, Fariborz, and myself,
in no particular order.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133103 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
John McCall 2011-06-15 23:02:42 +00:00
parent 204e13395d
commit f85e193739
198 changed files with 13874 additions and 1099 deletions

View File

@ -65,6 +65,7 @@ td {
<li><a href="#objc_features">Objective-C Features</a>
<ul>
<li><a href="#objc_instancetype">Related result types</a></li>
<li><a href="#objc_arc">Automatic reference counting</a></li>
</ul>
</li>
<li><a href="#overloading-in-c">Function Overloading in C</a></li>
@ -669,6 +670,12 @@ property access via the given method. In all other respects, a method
with a related result type is treated the same way as method without a
related result type.</p>
<!-- ======================================================================= -->
<h2 id="objc_arc">Automatic reference counting </h2>
<!-- ======================================================================= -->
<p>Clang provides support for <a href="AutomaticReferenceCounting.html">automated reference counting</a> in Objective-C, which eliminates the need for manual retain/release/autorelease message sends. There are two feature macros associated with automatic reference counting: <code>__has_feature(objc_arc)</code> indicates the availability of automated reference counting in general, while <code>__has_feature(objc_arc_weak)</code> indicates that automated reference counting also includes support for <code>__weak</code> pointers to Objective-C objects.</p>
<!-- ======================================================================= -->
<h2 id="overloading-in-c">Function Overloading in C</h2>
<!-- ======================================================================= -->

View File

@ -993,6 +993,18 @@ public:
return getExtQualType(T, Qs);
}
/// getLifetimeQualifiedType - Returns a type with the given
/// lifetime qualifier.
QualType getLifetimeQualifiedType(QualType type,
Qualifiers::ObjCLifetime lifetime) {
assert(type.getObjCLifetime() == Qualifiers::OCL_None);
assert(lifetime != Qualifiers::OCL_None);
Qualifiers qs;
qs.addObjCLifetime(lifetime);
return getQualifiedType(type, qs);
}
DeclarationNameInfo getNameForTemplate(TemplateName Name,
SourceLocation NameLoc) const;
@ -1044,7 +1056,9 @@ public:
/// isObjCNSObjectType - Return true if this is an NSObject object with
/// its NSObject attribute set.
bool isObjCNSObjectType(QualType Ty) const;
static bool isObjCNSObjectType(QualType Ty) {
return Ty->isObjCNSObjectType();
}
//===--------------------------------------------------------------------===//
// Type Sizing and Analysis

View File

@ -250,7 +250,6 @@ public:
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjectType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteOrObjectType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isPODType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVariablyModifiedType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIntegerType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isEnumeralType)
@ -295,6 +294,7 @@ public:
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnsignedIntegerOrEnumerationType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isConstantSizeType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSpecifierType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(CXXRecordDecl*, getAsCXXRecordDecl)
/// \brief Retrieve the proxy-adaptor type.
///

View File

@ -1240,6 +1240,9 @@ class ObjCImplementationDecl : public ObjCImplDecl {
/// IvarInitializers - The arguments used to initialize the ivars
CXXCtorInitializer **IvarInitializers;
unsigned NumIvarInitializers;
/// true if class has a .cxx_[construct,destruct] method.
bool HasCXXStructors : 1;
/// true of class extension has at least one bitfield ivar.
bool HasSynthBitfield : 1;
@ -1249,7 +1252,7 @@ class ObjCImplementationDecl : public ObjCImplDecl {
ObjCInterfaceDecl *superDecl)
: ObjCImplDecl(ObjCImplementation, DC, L, classInterface),
SuperClass(superDecl), IvarInitializers(0), NumIvarInitializers(0),
HasSynthBitfield(false) {}
HasCXXStructors(false), HasSynthBitfield(false) {}
public:
static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
@ -1287,6 +1290,9 @@ public:
void setIvarInitializers(ASTContext &C,
CXXCtorInitializer ** initializers,
unsigned numInitializers);
bool hasCXXStructors() const { return HasCXXStructors; }
void setHasCXXStructors(bool val) { HasCXXStructors = val; }
bool hasSynthBitfield() const { return HasSynthBitfield; }
void setHasSynthBitfield (bool val) { HasSynthBitfield = val; }
@ -1393,7 +1399,10 @@ public:
OBJC_PR_copy = 0x20,
OBJC_PR_nonatomic = 0x40,
OBJC_PR_setter = 0x80,
OBJC_PR_atomic = 0x100
OBJC_PR_atomic = 0x100,
OBJC_PR_weak = 0x200,
OBJC_PR_strong = 0x400,
OBJC_PR_unsafe_unretained = 0x800
};
enum SetterKind { Assign, Retain, Copy };
@ -1401,8 +1410,8 @@ public:
private:
SourceLocation AtLoc; // location of @property
TypeSourceInfo *DeclType;
unsigned PropertyAttributes : 9;
unsigned PropertyAttributesAsWritten : 9;
unsigned PropertyAttributes : 11;
unsigned PropertyAttributesAsWritten : 11;
// @required/@optional
unsigned PropertyImplementation : 2;
@ -1466,7 +1475,7 @@ public:
/// the property setter. This is only valid if the property has been
/// defined to have a setter.
SetterKind getSetterKind() const {
if (PropertyAttributes & OBJC_PR_retain)
if (PropertyAttributes & (OBJC_PR_retain|OBJC_PR_strong))
return Retain;
if (PropertyAttributes & OBJC_PR_copy)
return Copy;

View File

@ -2276,6 +2276,8 @@ private:
case CK_IntegralComplexToReal:
case CK_IntegralComplexCast:
case CK_IntegralComplexToFloatingComplex:
case CK_ObjCProduceObject:
case CK_ObjCConsumeObject:
assert(!getType()->isBooleanType() && "unheralded conversion to bool");
// fallthrough to check for null base path

View File

@ -456,7 +456,11 @@ class ObjCMessageExpr : public Expr {
///
/// When non-zero, we have a method declaration; otherwise, we just
/// have a selector.
unsigned HasMethod : 8;
unsigned HasMethod : 1;
/// \brief Whether this message send is a "delegate init call",
/// i.e. a call of an init method on self from within an init method.
unsigned IsDelegateInitCall : 1;
/// \brief When the message expression is a send to 'super', this is
/// the location of the 'super' keyword.
@ -476,7 +480,7 @@ class ObjCMessageExpr : public Expr {
ObjCMessageExpr(EmptyShell Empty, unsigned NumArgs)
: Expr(ObjCMessageExprClass, Empty), NumArgs(NumArgs), Kind(0),
HasMethod(0), SelectorOrMethod(0) { }
HasMethod(0), IsDelegateInitCall(0), SelectorOrMethod(0) { }
ObjCMessageExpr(QualType T, ExprValueKind VK,
SourceLocation LBracLoc,
@ -807,6 +811,12 @@ public:
getArgs()[Arg] = ArgExpr;
}
/// isDelegateInitCall - Answers whether this message send has been
/// tagged as a "delegate init call", i.e. a call to a method in the
/// -init family on self from within an -init method implementation.
bool isDelegateInitCall() const { return IsDelegateInitCall; }
void setDelegateInitCall(bool isDelegate) { IsDelegateInitCall = isDelegate; }
SourceLocation getLeftLoc() const { return LBracLoc; }
SourceLocation getRightLoc() const { return RBracLoc; }
SourceLocation getSelectorLoc() const { return SelectorLoc; }
@ -892,6 +902,122 @@ public:
child_range children() { return child_range(&Base, &Base+1); }
};
/// ObjCIndirectCopyRestoreExpr - Represents the passing of a function
/// argument by indirect copy-restore in ARC. This is used to support
/// passing indirect arguments with the wrong lifetime, e.g. when
/// passing the address of a __strong local variable to an 'out'
/// parameter. This expression kind is only valid in an "argument"
/// position to some sort of call expression.
///
/// The parameter must have type 'pointer to T', and the argument must
/// have type 'pointer to U', where T and U agree except possibly in
/// qualification. If the argument value is null, then a null pointer
/// is passed; otherwise it points to an object A, and:
/// 1. A temporary object B of type T is initialized, either by
/// zero-initialization (used when initializing an 'out' parameter)
/// or copy-initialization (used when initializing an 'inout'
/// parameter).
/// 2. The address of the temporary is passed to the function.
/// 3. If the call completes normally, A is move-assigned from B.
/// 4. Finally, A is destroyed immediately.
///
/// Currently 'T' must be a retainable object lifetime and must be
/// __autoreleasing; this qualifier is ignored when initializing
/// the value.
class ObjCIndirectCopyRestoreExpr : public Expr {
Stmt *Operand;
// unsigned ObjCIndirectCopyRestoreBits.ShouldCopy : 1;
friend class ASTReader;
friend class ASTStmtReader;
void setShouldCopy(bool shouldCopy) {
ObjCIndirectCopyRestoreExprBits.ShouldCopy = shouldCopy;
}
explicit ObjCIndirectCopyRestoreExpr(EmptyShell Empty)
: Expr(ObjCIndirectCopyRestoreExprClass, Empty) { }
public:
ObjCIndirectCopyRestoreExpr(Expr *operand, QualType type, bool shouldCopy)
: Expr(ObjCIndirectCopyRestoreExprClass, type, VK_LValue, OK_Ordinary,
operand->isTypeDependent(), operand->isValueDependent(),
operand->containsUnexpandedParameterPack()),
Operand(operand) {
setShouldCopy(shouldCopy);
}
Expr *getSubExpr() { return cast<Expr>(Operand); }
const Expr *getSubExpr() const { return cast<Expr>(Operand); }
/// shouldCopy - True if we should do the 'copy' part of the
/// copy-restore. If false, the temporary will be zero-initialized.
bool shouldCopy() const { return ObjCIndirectCopyRestoreExprBits.ShouldCopy; }
child_range children() { return child_range(&Operand, &Operand+1); }
// Source locations are determined by the subexpression.
SourceRange getSourceRange() const { return Operand->getSourceRange(); }
SourceLocation getExprLoc() const { return getSubExpr()->getExprLoc(); }
static bool classof(const Stmt *s) {
return s->getStmtClass() == ObjCIndirectCopyRestoreExprClass;
}
static bool classof(const ObjCIndirectCopyRestoreExpr *) { return true; }
};
/// \brief An Objective-C "bridged" cast expression, which casts between
/// Objective-C pointers and C pointers, transferring ownership in the process.
///
/// \code
/// NSString *str = (__bridge_transfer NSString *)CFCreateString();
/// \endcode
class ObjCBridgedCastExpr : public ExplicitCastExpr {
SourceLocation LParenLoc;
SourceLocation BridgeKeywordLoc;
unsigned Kind : 2;
friend class ASTStmtReader;
friend class ASTStmtWriter;
public:
ObjCBridgedCastExpr(SourceLocation LParenLoc, ObjCBridgeCastKind Kind,
SourceLocation BridgeKeywordLoc, TypeSourceInfo *TSInfo,
Expr *Operand)
: ExplicitCastExpr(ObjCBridgedCastExprClass, TSInfo->getType(), VK_RValue,
CK_BitCast, Operand, 0, TSInfo),
LParenLoc(LParenLoc), BridgeKeywordLoc(BridgeKeywordLoc), Kind(Kind) { }
/// \brief Construct an empty Objective-C bridged cast.
explicit ObjCBridgedCastExpr(EmptyShell Shell)
: ExplicitCastExpr(ObjCBridgedCastExprClass, Shell, 0) { }
SourceLocation getLParenLoc() const { return LParenLoc; }
/// \brief Determine which kind of bridge is being performed via this cast.
ObjCBridgeCastKind getBridgeKind() const {
return static_cast<ObjCBridgeCastKind>(Kind);
}
/// \brief Retrieve the kind of bridge being performed as a string.
llvm::StringRef getBridgeKindName() const;
/// \brief The location of the bridge keyword.
SourceLocation getBridgeKeywordLoc() const { return BridgeKeywordLoc; }
SourceRange getSourceRange() const {
return SourceRange(LParenLoc, getSubExpr()->getLocEnd());
}
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCBridgedCastExprClass;
}
static bool classof(const ObjCBridgedCastExpr *) { return true; }
};
} // end namespace clang
#endif

View File

@ -245,7 +245,17 @@ enum CastKind {
/// \brief Converts from an integral complex to a floating complex.
/// _Complex unsigned -> _Complex float
CK_IntegralComplexToFloatingComplex
CK_IntegralComplexToFloatingComplex,
/// \brief Produces an Objective-C object so that it may be
/// consumed, e.g. by being passed to a consuming parameter. Calls
/// objc_retain.
CK_ObjCProduceObject,
/// \brief Consumes an Objective-C object that has just been
/// produced, e.g. as the return value of a retaining call. Enters
/// a cleanup to call objc_release at some indefinite time.
CK_ObjCConsumeObject
};
#define CK_Invalid ((CastKind) -1)
@ -284,6 +294,19 @@ enum UnaryOperatorKind {
UO_Extension // __extension__ marker.
};
/// \brief The kind of bridging performed by the Objective-C bridge cast.
enum ObjCBridgeCastKind {
/// \brief Bridging via __bridge, which does nothing but reinterpret
/// the bits.
OBC_Bridge,
/// \brief Bridging via __bridge_transfer, which transfers ownership of an
/// Objective-C pointer into ARC.
OBC_BridgeTransfer,
/// \brief Bridging via __bridge_retain, which makes an ARC object available
/// as a +1 C pointer.
OBC_BridgeRetained
};
}
#endif

View File

@ -32,6 +32,7 @@ public:
Stmt *getParent(Stmt*) const;
Stmt *getParentIgnoreParens(Stmt *) const;
Stmt *getParentIgnoreParenCasts(Stmt *) const;
Stmt *getOuterParenParent(Stmt *) const;
const Stmt *getParent(const Stmt* S) const {
return getParent(const_cast<Stmt*>(S));

View File

@ -41,7 +41,7 @@ struct PrintingPolicy {
SuppressTagKeyword(false), SuppressTag(false), SuppressScope(false),
SuppressInitializers(false),
Dump(false), ConstantArraySizeAsWritten(false),
AnonymousTagLocations(true) { }
AnonymousTagLocations(true), SuppressStrongLifetime(false) { }
/// \brief The number of spaces to use to indent each line.
unsigned Indentation : 8;
@ -129,6 +129,10 @@ struct PrintingPolicy {
/// that entity (e.g., "enum <anonymous at t.h:10:5>"). Otherwise, just
/// prints "<anonymous>" for the name.
bool AnonymousTagLocations : 1;
/// \brief When true, suppress printing of the __strong lifetime qualifier in
/// ARC.
unsigned SuppressStrongLifetime : 1;
};
} // end namespace clang

View File

@ -1721,6 +1721,7 @@ DEF_TRAVERSE_STMT(ObjCAtSynchronizedStmt, { })
DEF_TRAVERSE_STMT(ObjCAtThrowStmt, { })
DEF_TRAVERSE_STMT(ObjCAtTryStmt, { })
DEF_TRAVERSE_STMT(ObjCForCollectionStmt, { })
DEF_TRAVERSE_STMT(ObjCAutoreleasePoolStmt, { })
DEF_TRAVERSE_STMT(CXXForRangeStmt, { })
DEF_TRAVERSE_STMT(ReturnStmt, { })
DEF_TRAVERSE_STMT(SwitchStmt, { })
@ -1933,6 +1934,10 @@ DEF_TRAVERSE_STMT(ObjCMessageExpr, { })
DEF_TRAVERSE_STMT(ObjCPropertyRefExpr, { })
DEF_TRAVERSE_STMT(ObjCProtocolExpr, { })
DEF_TRAVERSE_STMT(ObjCSelectorExpr, { })
DEF_TRAVERSE_STMT(ObjCIndirectCopyRestoreExpr, { })
DEF_TRAVERSE_STMT(ObjCBridgedCastExpr, {
TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
})
DEF_TRAVERSE_STMT(ParenExpr, { })
DEF_TRAVERSE_STMT(ParenListExpr, { })
DEF_TRAVERSE_STMT(PredefinedExpr, { })

View File

@ -183,6 +183,13 @@ protected:
unsigned NumPreArgs : 1;
};
class ObjCIndirectCopyRestoreExprBitfields {
friend class ObjCIndirectCopyRestoreExpr;
unsigned : NumExprBits;
unsigned ShouldCopy : 1;
};
union {
// FIXME: this is wasteful on 64-bit platforms.
void *Aligner;
@ -193,6 +200,7 @@ protected:
DeclRefExprBitfields DeclRefExprBits;
CastExprBitfields CastExprBits;
CallExprBitfields CallExprBits;
ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits;
};
friend class ASTStmtReader;

View File

@ -342,6 +342,39 @@ public:
child_range children() { return child_range(&Throw, &Throw+1); }
};
/// ObjCAutoreleasePoolStmt - This represent objective-c's
/// @autoreleasepool Statement
class ObjCAutoreleasePoolStmt : public Stmt {
Stmt *SubStmt;
SourceLocation AtLoc;
public:
ObjCAutoreleasePoolStmt(SourceLocation atLoc,
Stmt *subStmt)
: Stmt(ObjCAutoreleasePoolStmtClass),
SubStmt(subStmt), AtLoc(atLoc) {}
explicit ObjCAutoreleasePoolStmt(EmptyShell Empty) :
Stmt(ObjCAutoreleasePoolStmtClass, Empty) { }
const Stmt *getSubStmt() const { return SubStmt; }
Stmt *getSubStmt() { return SubStmt; }
void setSubStmt(Stmt *S) { SubStmt = S; }
SourceRange getSourceRange() const {
return SourceRange(AtLoc, SubStmt->getLocEnd());
}
SourceLocation getAtLoc() const { return AtLoc; }
void setAtLoc(SourceLocation Loc) { AtLoc = Loc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCAutoreleasePoolStmtClass;
}
static bool classof(const ObjCAutoreleasePoolStmt *) { return true; }
child_range children() { return child_range(&SubStmt, &SubStmt + 1); }
};
} // end namespace clang
#endif

View File

@ -126,6 +126,28 @@ public:
Strong
};
enum ObjCLifetime {
/// There is no lifetime qualification on this type.
OCL_None,
/// This object can be modified without requiring retains or
/// releases.
OCL_ExplicitNone,
/// Assigning into this object requires the old value to be
/// released and the new value to be retained. The timing of the
/// release of the old value is inexact: it may be moved to
/// immediately after the last known point where the value is
/// live.
OCL_Strong,
/// Reading or writing from this object requires a barrier call.
OCL_Weak,
/// Assigning into this object requires a lifetime extension.
OCL_Autoreleasing
};
enum {
/// The maximum supported address space number.
/// 24 bits should be enough for anyone.
@ -218,7 +240,37 @@ public:
qs.removeObjCGCAttr();
return qs;
}
Qualifiers withoutObjCGLifetime() const {
Qualifiers qs = *this;
qs.removeObjCLifetime();
return qs;
}
bool hasObjCLifetime() const { return Mask & LifetimeMask; }
ObjCLifetime getObjCLifetime() const {
return ObjCLifetime((Mask & LifetimeMask) >> LifetimeShift);
}
void setObjCLifetime(ObjCLifetime type) {
Mask = (Mask & ~LifetimeMask) | (type << LifetimeShift);
}
void removeObjCLifetime() { setObjCLifetime(OCL_None); }
void addObjCLifetime(ObjCLifetime type) {
assert(type);
setObjCLifetime(type);
}
/// True if the lifetime is neither None or ExplicitNone.
bool hasNonTrivialObjCLifetime() const {
ObjCLifetime lifetime = getObjCLifetime();
return (lifetime > OCL_ExplicitNone);
}
/// True if the lifetime is either strong or weak.
bool hasStrongOrWeakObjCLifetime() const {
ObjCLifetime lifetime = getObjCLifetime();
return (lifetime == OCL_Strong || lifetime == OCL_Weak);
}
bool hasAddressSpace() const { return Mask & AddressSpaceMask; }
unsigned getAddressSpace() const { return Mask >> AddressSpaceShift; }
void setAddressSpace(unsigned space) {
@ -277,6 +329,8 @@ public:
addAddressSpace(Q.getAddressSpace());
if (Q.hasObjCGCAttr())
addObjCGCAttr(Q.getObjCGCAttr());
if (Q.hasObjCLifetime())
addObjCLifetime(Q.getObjCLifetime());
}
}
@ -287,6 +341,8 @@ public:
!hasAddressSpace() || !qs.hasAddressSpace());
assert(getObjCGCAttr() == qs.getObjCGCAttr() ||
!hasObjCGCAttr() || !qs.hasObjCGCAttr());
assert(getObjCLifetime() == qs.getObjCLifetime() ||
!hasObjCLifetime() || !qs.hasObjCLifetime());
Mask |= qs.Mask;
}
@ -301,10 +357,30 @@ public:
// changed.
(getObjCGCAttr() == other.getObjCGCAttr() ||
!hasObjCGCAttr() || !other.hasObjCGCAttr()) &&
// ObjC lifetime qualifiers must match exactly.
getObjCLifetime() == other.getObjCLifetime() &&
// CVR qualifiers may subset.
(((Mask & CVRMask) | (other.Mask & CVRMask)) == (Mask & CVRMask));
}
/// \brief Determines if these qualifiers compatibly include another set of
/// qualifiers from the narrow perspective of Objective-C ARC lifetime.
///
/// One set of Objective-C lifetime qualifiers compatibly includes the other
/// if the lifetime qualifiers match, or if both are non-__weak and the
/// including set also contains the 'const' qualifier.
bool compatiblyIncludesObjCLifetime(Qualifiers other) const {
if (getObjCLifetime() == other.getObjCLifetime())
return true;
if (getObjCLifetime() == OCL_Weak || other.getObjCLifetime() == OCL_Weak)
return false;
return hasConst();
}
bool isSupersetOf(Qualifiers Other) const;
/// \brief Determine whether this set of qualifiers is a strict superset of
/// another set of qualifiers, not considering qualifier compatibility.
bool isStrictSupersetOf(Qualifiers Other) const;
@ -351,14 +427,16 @@ public:
private:
// bits: |0 1 2|3 .. 4|5 .. 31|
// |C R V|GCAttr|AddrSpace|
// bits: |0 1 2|3 .. 4|5 .. 7|8 ... 31|
// |C R V|GCAttr|Lifetime|AddressSpace|
uint32_t Mask;
static const uint32_t GCAttrMask = 0x18;
static const uint32_t GCAttrShift = 3;
static const uint32_t AddressSpaceMask = ~(CVRMask | GCAttrMask);
static const uint32_t AddressSpaceShift = 5;
static const uint32_t LifetimeMask = 0xE0;
static const uint32_t LifetimeShift = 5;
static const uint32_t AddressSpaceMask = ~(CVRMask|GCAttrMask|LifetimeMask);
static const uint32_t AddressSpaceShift = 8;
};
/// CallingConv - Specifies the calling convention that a function uses.
@ -527,6 +605,23 @@ public:
return QualType::isConstant(*this, Ctx);
}
/// \brief Determine whether this is a Plain Old Data (POD) type (C++ 3.9p10).
bool isPODType(ASTContext &Context) const;
/// isCXX11PODType() - Return true if this is a POD type according to the
/// more relaxed rules of the C++11 standard, regardless of the current
/// compilation's language.
/// (C++0x [basic.types]p9)
bool isCXX11PODType(ASTContext &Context) const;
/// isTrivialType - Return true if this is a trivial type
/// (C++0x [basic.types]p9)
bool isTrivialType(ASTContext &Context) const;
/// isTriviallyCopyableType - Return true if this is a trivially
/// copyable type (C++0x [basic.types]p9)
bool isTriviallyCopyableType(ASTContext &Context) const;
// Don't promise in the API that anything besides 'const' can be
// easily added.
@ -709,7 +804,7 @@ public:
/// getAddressSpace - Return the address space of this type.
inline unsigned getAddressSpace() const;
/// GCAttrTypesAttr - Returns gc attribute of this type.
/// getObjCGCAttr - Returns gc attribute of this type.
inline Qualifiers::GC getObjCGCAttr() const;
/// isObjCGCWeak true when Type is objc's weak.
@ -722,9 +817,24 @@ public:
return getObjCGCAttr() == Qualifiers::Strong;
}
/// getObjCLifetime - Returns lifetime attribute of this type.
Qualifiers::ObjCLifetime getObjCLifetime() const {
return getQualifiers().getObjCLifetime();
}
bool hasNonTrivialObjCLifetime() const {
return getQualifiers().hasNonTrivialObjCLifetime();
}
bool hasStrongOrWeakObjCLifetime() const {
return getQualifiers().hasStrongOrWeakObjCLifetime();
}
enum DestructionKind {
DK_none,
DK_cxx_destructor
DK_cxx_destructor,
DK_objc_strong_lifetime,
DK_objc_weak_lifetime
};
/// isDestructedType - nonzero if objects of this type require
@ -735,6 +845,9 @@ public:
return isDestructedTypeImpl(*this);
}
/// \brief Determine whether this type has trivial copy-assignment semantics.
bool hasTrivialCopyAssignment(ASTContext &Context) const;
private:
// These methods are implemented in a separate translation unit;
// "static"-ize them to avoid creating temporary QualTypes in the
@ -849,6 +962,11 @@ public:
bool hasObjCGCAttr() const { return Quals.hasObjCGCAttr(); }
Qualifiers::GC getObjCGCAttr() const { return Quals.getObjCGCAttr(); }
bool hasObjCLifetime() const { return Quals.hasObjCLifetime(); }
Qualifiers::ObjCLifetime getObjCLifetime() const {
return Quals.getObjCLifetime();
}
bool hasAddressSpace() const { return Quals.hasAddressSpace(); }
unsigned getAddressSpace() const { return Quals.getAddressSpace(); }
@ -1005,7 +1123,7 @@ protected:
/// Extra information which affects how the function is called, like
/// regparm and the calling convention.
unsigned ExtInfo : 8;
unsigned ExtInfo : 9;
/// Whether the function is variadic. Only used by FunctionProtoType.
unsigned Variadic : 1;
@ -1186,31 +1304,14 @@ public:
return !isReferenceType() && !isFunctionType() && !isVoidType();
}
/// isPODType - Return true if this is a plain-old-data type (C++ 3.9p10).
bool isPODType() const;
/// isLiteralType - Return true if this is a literal type
/// (C++0x [basic.types]p10)
bool isLiteralType() const;
/// isTrivialType - Return true if this is a trivial type
/// (C++0x [basic.types]p9)
bool isTrivialType() const;
/// isTriviallyCopyableType - Return true if this is a trivially copyable type
/// (C++0x [basic.types]p9
bool isTriviallyCopyableType() const;
/// \brief Test if this type is a standard-layout type.
/// (C++0x [basic.type]p9)
bool isStandardLayoutType() const;
/// isCXX11PODType() - Return true if this is a POD type according to the
/// more relaxed rules of the C++11 standard, regardless of the current
/// compilation's language.
/// (C++0x [basic.types]p9)
bool isCXX11PODType() const;
/// Helper methods to distinguish type categories. All type predicates
/// operate on the canonical type, ignoring typedefs and qualifiers.
@ -1290,7 +1391,11 @@ public:
bool isComplexIntegerType() const; // GCC _Complex integer type.
bool isVectorType() const; // GCC vector type.
bool isExtVectorType() const; // Extended vector type.
bool isObjCObjectPointerType() const; // Pointer to *any* ObjC object.
bool isObjCObjectPointerType() const; // pointer to ObjC object
bool isObjCRetainableType() const; // ObjC object or block pointer
bool isObjCLifetimeType() const; // (array of)* retainable type
bool isObjCIndirectLifetimeType() const; // (pointer to)* lifetime type
bool isObjCNSObjectType() const; // __attribute__((NSObject))
// FIXME: change this to 'raw' interface type, so we can used 'interface' type
// for the common case.
bool isObjCObjectType() const; // NSString or typeof(*(id)0)
@ -1302,9 +1407,19 @@ public:
bool isObjCClassType() const; // Class
bool isObjCSelType() const; // Class
bool isObjCBuiltinType() const; // 'id' or 'Class'
bool isObjCARCBridgableType() const;
bool isCARCBridgableType() const;
bool isTemplateTypeParmType() const; // C++ template type parameter
bool isNullPtrType() const; // C++0x nullptr_t
/// Determines if this type, which must satisfy
/// isObjCLifetimeType(), is implicitly __unsafe_unretained rather
/// than implicitly __strong.
bool isObjCARCImplicitlyUnretainedType() const;
/// Return the implicit lifetime for this type, which must not be dependent.
Qualifiers::ObjCLifetime getObjCARCImplicitLifetime() const;
enum ScalarTypeKind {
STK_Pointer,
STK_MemberPointer,
@ -1480,6 +1595,7 @@ public:
}
CanQualType getCanonicalTypeUnqualified() const; // in CanonicalType.h
void dump() const;
static bool classof(const Type *) { return true; }
friend class ASTReader;
@ -2340,30 +2456,33 @@ class FunctionType : public Type {
// * AST read and write
// * Codegen
class ExtInfo {
// Feel free to rearrange or add bits, but if you go over 8,
// Feel free to rearrange or add bits, but if you go over 9,
// you'll need to adjust both the Bits field below and
// Type::FunctionTypeBitfields.
// | CC |noreturn|hasregparm|regparm
// |0 .. 2| 3 | 4 |5 .. 7
// | CC |noreturn|produces|hasregparm|regparm
// |0 .. 2| 3 | 4 | 5 |6 .. 8
enum { CallConvMask = 0x7 };
enum { NoReturnMask = 0x8 };
enum { HasRegParmMask = 0x10 };
enum { RegParmMask = ~(CallConvMask | NoReturnMask),
RegParmOffset = 5 };
enum { ProducesResultMask = 0x10 };
enum { HasRegParmMask = 0x20 };
enum { RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask),
RegParmOffset = 6 }; // Assumed to be the last field
unsigned char Bits;
uint16_t Bits;
ExtInfo(unsigned Bits) : Bits(static_cast<unsigned char>(Bits)) {}
ExtInfo(unsigned Bits) : Bits(static_cast<uint16_t>(Bits)) {}
friend class FunctionType;
public:
// Constructor with no defaults. Use this when you know that you
// have all the elements (when reading an AST file for example).
ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc) {
ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc,
bool producesResult) {
Bits = ((unsigned) cc) |
(noReturn ? NoReturnMask : 0) |
(producesResult ? ProducesResultMask : 0) |
(hasRegParm ? HasRegParmMask : 0) |
(regParm << RegParmOffset);
}
@ -2373,6 +2492,7 @@ class FunctionType : public Type {
ExtInfo() : Bits(0) {}
bool getNoReturn() const { return Bits & NoReturnMask; }
bool getProducesResult() const { return Bits & ProducesResultMask; }
bool getHasRegParm() const { return Bits & HasRegParmMask; }
unsigned getRegParm() const { return Bits >> RegParmOffset; }
CallingConv getCC() const { return CallingConv(Bits & CallConvMask); }
@ -2394,8 +2514,17 @@ class FunctionType : public Type {
return ExtInfo(Bits & ~NoReturnMask);
}
ExtInfo withProducesResult(bool producesResult) const {
if (producesResult)
return ExtInfo(Bits | ProducesResultMask);
else
return ExtInfo(Bits & ~ProducesResultMask);
}
ExtInfo withRegParm(unsigned RegParm) const {
return ExtInfo(HasRegParmMask | (Bits & ~RegParmMask) | (RegParm << RegParmOffset));
return ExtInfo((Bits & ~RegParmMask) |
(HasRegParmMask) |
(RegParm << RegParmOffset));
}
ExtInfo withCallingConv(CallingConv cc) const {
@ -2495,7 +2624,8 @@ public:
struct ExtProtoInfo {
ExtProtoInfo() :
Variadic(false), ExceptionSpecType(EST_None), TypeQuals(0),
RefQualifier(RQ_None), NumExceptions(0), Exceptions(0), NoexceptExpr(0) {}
RefQualifier(RQ_None), NumExceptions(0), Exceptions(0), NoexceptExpr(0),
ConsumedArguments(0) {}
FunctionType::ExtInfo ExtInfo;
bool Variadic;
@ -2505,6 +2635,7 @@ public:
unsigned NumExceptions;
const QualType *Exceptions;
Expr *NoexceptExpr;
const bool *ConsumedArguments;
};
private:
@ -2523,7 +2654,7 @@ private:
QualType canonical, const ExtProtoInfo &epi);
/// NumArgs - The number of arguments this function has, not counting '...'.
unsigned NumArgs : 20;
unsigned NumArgs : 19;
/// NumExceptions - The number of types in the exception spec, if any.
unsigned NumExceptions : 9;
@ -2531,6 +2662,9 @@ private:
/// ExceptionSpecType - The type of exception specification this function has.
unsigned ExceptionSpecType : 3;
/// HasAnyConsumedArgs - Whether this function has any consumed arguments.
unsigned HasAnyConsumedArgs : 1;
/// ArgInfo - There is an variable size array after the class in memory that
/// holds the argument types.
@ -2540,8 +2674,25 @@ private:
/// NoexceptExpr - Instead of Exceptions, there may be a single Expr* pointing
/// to the expression in the noexcept() specifier.
/// ConsumedArgs - A variable size array, following Exceptions
/// and of length NumArgs, holding flags indicating which arguments
/// are consumed. This only appears if HasAnyConsumedArgs is true.
friend class ASTContext; // ASTContext creates these.
const bool *getConsumedArgsBuffer() const {
assert(hasAnyConsumedArgs());
// Find the end of the exceptions.
Expr * const *eh_end = reinterpret_cast<Expr * const *>(arg_type_end());
if (getExceptionSpecType() != EST_ComputedNoexcept)
eh_end += NumExceptions;
else
eh_end += 1; // NoexceptExpr
return reinterpret_cast<const bool*>(eh_end);
}
public:
unsigned getNumArgs() const { return NumArgs; }
QualType getArgType(unsigned i) const {
@ -2562,6 +2713,8 @@ public:
} else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
EPI.NoexceptExpr = getNoexceptExpr();
}
if (hasAnyConsumedArgs())
EPI.ConsumedArguments = getConsumedArgsBuffer();
return EPI;
}
@ -2647,6 +2800,16 @@ public:
return exception_begin() + NumExceptions;
}
bool hasAnyConsumedArgs() const {
return HasAnyConsumedArgs;
}
bool isArgConsumed(unsigned I) const {
assert(I < getNumArgs() && "argument index out of range!");
if (hasAnyConsumedArgs())
return getConsumedArgsBuffer()[I];
return false;
}
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
@ -2971,6 +3134,7 @@ public:
// Enumerated operand (string or keyword).
attr_objc_gc,
attr_objc_lifetime,
attr_pcs,
FirstEnumOperandKind = attr_objc_gc,

View File

@ -400,6 +400,11 @@ def ObjCNSObject : InheritableAttr {
let Spellings = ["NSObject"];
}
def ObjCPreciseLifetime : Attr {
let Spellings = ["objc_precise_lifetime"];
let Subjects = [Var];
}
def Overloadable : Attr {
let Spellings = ["overloadable"];
}

View File

@ -32,6 +32,7 @@ def note_type_being_defined : Note<
def note_matching : Note<"to match this '%0'">;
def note_using : Note<"using">;
def note_possibility : Note<"one possibility">;
def note_also_found : Note<"also found">;
// Parse && Lex

View File

@ -82,6 +82,10 @@ def err_drv_conflicting_deployment_targets : Error<
"conflicting deployment targets, both '%0' and '%1' are present in environment">;
def err_drv_invalid_arch_for_deployment_target : Error<
"invalid architecture '%0' for deployment target '%1'">;
def err_drv_objc_gc_arr : Error<
"cannot specify both '-fobjc-arc' and '%0'">;
def err_arc_nonfragile_abi : Error<
"-fobjc-arc is not supported with fragile abi">;
def warn_c_kext : Warning<
"ignoring -fapple-kext which is valid for c++ and objective-c++ only">;

View File

@ -137,6 +137,9 @@ def warn_pch_nonfragile_abi2 : Error<
"PCH file was compiled with the %select{32-bit|enhanced non-fragile}0 "
"Objective-C ABI but the %select{32-bit|enhanced non-fragile}1 "
"Objective-C ABI is selected">;
def warn_pch_auto_ref_count : Error<
"PCH file was compiled %select{without|with} automated reference counting,"
"which is currently %select{disabled|enabled}">;
def warn_pch_apple_kext : Error<
"PCH file was compiled %select{with|without}0 support for Apple's kernel "
"extensions ABI but it is currently %select{disabled|enabled}1">;

View File

@ -169,6 +169,8 @@ def ImplicitAtomic : DiagGroup<"implicit-atomic-properties">;
def CustomAtomic : DiagGroup<"custom-atomic-properties">;
def AtomicProperties : DiagGroup<"atomic-properties",
[ImplicitAtomic, CustomAtomic]>;
def AutomaticReferenceCountingABI : DiagGroup<"arc-abi">;
def AutomaticReferenceCounting : DiagGroup<"arc", [AutomaticReferenceCountingABI]>;
def Selector : DiagGroup<"selector">;
def NonfragileAbi2 : DiagGroup<"nonfragile-abi2">;
def Protocol : DiagGroup<"protocol">;

View File

@ -430,6 +430,12 @@ def warn_objc_property_copy_missing_on_block : Warning<
def warn_atomic_property_rule : Warning<
"writable atomic property %0 cannot pair a synthesized setter/getter "
"with a user defined setter/getter">;
def warn_ownin_getter_rule : Warning<
"property's synthesized getter follows Cocoa naming"
" convention for returning 'owned' objects">;
def err_ownin_getter_rule : Error<
"property's synthesized getter follows Cocoa naming"
" convention for returning 'owned' objects">;
def warn_default_atomic_custom_getter_setter : Warning<
"atomic by default property %0 has a user defined %select{getter|setter}1 "
"(property should be marked 'atomic' if this is intended)">,
@ -465,6 +471,8 @@ def error_bad_property_context : Error<
def error_missing_property_ivar_decl : Error<
"synthesized property %0 must either be named the same as a compatible"
" ivar or must explicitly name an ivar">;
def error_synthesize_weak_non_arc_or_gc : Error<
"@synthesize of 'weak' property is only allowed in ARC or GC mode">;
def error_synthesized_ivar_yet_not_supported : Error<
"instance variable synthesis not yet supported"
@ -477,7 +485,7 @@ def error_ivar_in_superclass_use : Error<
def error_weak_property : Error<
"existing ivar %1 for __weak property %0 must be __weak">;
def error_strong_property : Error<
"property %0 must be declared __weak to match existing ivar %1 with __weak attribute">;
"existing ivar %1 for strong property %0 may not be __weak">;
def error_dynamic_property_ivar_decl : Error<
"dynamic property can not have ivar specification">;
def error_duplicate_ivar_use : Error<
@ -1138,6 +1146,8 @@ def err_format_attribute_implicit_this_format_string : Error<
"format attribute cannot specify the implicit this argument as the format "
"string">;
def warn_unknown_method_family : Warning<"unrecognized method family">;
def err_init_method_bad_return_type : Error<
"init methods must return an object pointer type, not %0">;
def err_attribute_invalid_size : Error<
"vector size not an integral multiple of component size">;
def err_attribute_zero_size : Error<"zero vector size">;
@ -1163,6 +1173,10 @@ def err_as_qualified_auto_decl : Error<
"automatic variable qualified with an address space">;
def err_arg_with_address_space : Error<
"parameter may not be qualified with an address space">;
def err_attr_objc_lifetime_bad_type : Error<
"the type %0 cannot be retained">;
def err_attr_objc_lifetime_redundant : Error<
"the type %0 already has retainment attributes set on it">;
def err_attribute_not_string : Error<
"argument to %0 attribute was not a string literal">;
def err_attribute_section_invalid_for_target : Error<
@ -1235,6 +1249,13 @@ def err_cconv_varargs : Error<
def err_regparm_mismatch : Error<"function declared with with regparm(%0) "
"attribute was previously declared "
"%plural{0:without the regparm|:with the regparm(%1)}1 attribute">;
def err_objc_precise_lifetime_bad_type : Error<
"objc_precise_lifetime only applies to retainable types; type here is %0">;
def warn_objc_precise_lifetime_meaningless : Error<
"objc_precise_lifetime is not meaningful for "
"%select{__unsafe_unretained|__autoreleasing}0 objects">;
def warn_label_attribute_not_unused : Warning<
"The only valid attribute for labels is 'unused'">;
def err_invalid_pcs : Error<"Invalid PCS type">;
// Availability attribute
@ -1569,6 +1590,17 @@ def note_ovl_candidate_bad_gc : Note<"candidate "
"constructor (inherited)}0%1 not viable: "
"%select{%ordinal6|'this'}5 argument (%2) has %select{no|__weak|__strong}3 "
"lifetime, but parameter has %select{no|__weak|__strong}4 lifetime">;
def note_ovl_candidate_bad_lifetime : Note<"candidate "
"%select{function|function|constructor|"
"function |function |constructor |"
"constructor (the implicit default constructor)|"
"constructor (the implicit copy constructor)|"
"function (the implicit copy assignment operator)|"
"constructor (inherited)}0%1 not viable: "
"%select{%ordinal6|'this'}5 argument (%2) has "
"%select{no|__unsafe_unretained|__strong|__weak|__autoreleasing}3 lifetime,"
" but parameter has %select{no|__unsafe_unretained|__strong|__weak|"
"__autoreleasing}4 lifetime">;
def note_ovl_candidate_bad_cvr_this : Note<"candidate "
"%select{|function|||function||||"
"function (the implicit copy assignment operator)|}0 not viable: "
@ -2202,8 +2234,8 @@ def err_unavailable_message : Error<"%0 is unavailable: %1">;
def warn_unavailable_fwdclass_message : Warning<
"%0 maybe unavailable because receiver type is unknown">;
def note_unavailable_here : Note<
"function has been explicitly marked "
"%select{unavailable|deleted|deprecated}0 here">;
"%select{declaration|function}0 has been explicitly marked "
"%select{unavailable|deleted|deprecated}1 here">;
def warn_not_enough_argument : Warning<
"not enough variable arguments in %0 declaration to fit a sentinel">;
def warn_missing_sentinel : Warning <
@ -2439,12 +2471,16 @@ def note_protected_by_objc_finally : Note<
"jump bypasses initialization of @finally block">;
def note_protected_by_objc_synchronized : Note<
"jump bypasses initialization of @synchronized block">;
def note_protected_by_objc_autoreleasepool : Note<
"jump bypasses auto release push of @autoreleasepool block">;
def note_protected_by_cxx_try : Note<
"jump bypasses initialization of try block">;
def note_protected_by_cxx_catch : Note<
"jump bypasses initialization of catch block">;
def note_protected_by___block : Note<
"jump bypasses setup of __block variable">;
def note_protected_by_objc_lifetime : Note<
"jump bypasses initialization of retaining variable">;
def note_exits_cleanup : Note<
"jump exits scope of variable with __attribute__((cleanup))">;
@ -2464,6 +2500,10 @@ def note_exits_cxx_try : Note<
"jump exits try block">;
def note_exits_cxx_catch : Note<
"jump exits catch block">;
def note_exits_objc_autoreleasepool : Note<
"jump exits autoreleasepool block">;
def note_exits_objc_lifetime : Note<
"jump exits scope of retaining variable">;
def err_func_returning_array_function : Error<
"function cannot return %select{array|function}0 type %1">;
@ -2495,6 +2535,139 @@ def ext_flexible_array_empty_aggregate_gnu : Extension<
def ext_flexible_array_union_gnu : Extension<
"flexible array member %0 in a union is a GNU extension">, InGroup<GNU>;
let CategoryName = "Automatic Reference Counting Issue" in {
// ARC-mode diagnostics.
def err_arc_weak_no_runtime : Error<
"the current deployment target does not support automated __weak references">;
def err_arc_illegal_explicit_message : Error<
"ARC forbids explicit message send of %0">;
def err_arc_unused_init_message : Error<
"the result of a delegate init call must be immediately returned "
"or assigned to 'self'">;
def err_arc_mismatched_cast : Error<
"%select{implicit conversion|cast}0 of "
"%select{%2|a non-Objective-C pointer type %2|a block pointer|"
"an Objective-C pointer|an indirect pointer to an Objective-C pointer}1"
" to %3 is disallowed with ARC">;
def err_arc_objc_object_in_struct : Error<
"ARC forbids Objective-C objects in structs or unions">;
def err_arc_objc_property_default_assign_on_object : Error<
"ARC forbids properties of Objective-C objects "
"with unspecified storage attribute">;
def err_arc_illegal_selector : Error<
"ARC forbids use of %0 in a @selector">;
def err_arc_illegal_method_def : Error<
"ARC forbids implementation of %0">;
def err_arc_lost_method_convention : Error<
"method was declared as %select{an 'alloc'|a 'copy'|an 'init'|a 'new'}0 "
"method, but its implementation doesn't match because %select{"
"its result type is not an object pointer|"
"its result type is unrelated to its receiver type}1">;
def note_arc_lost_method_convention : Note<"declaration in interface">;
def err_arc_gained_method_convention : Error<
"method implementation does not match its declaration">;
def note_arc_gained_method_convention : Note<
"declaration in interface is not in the '%select{alloc|copy|init|new}0' "
"family because %select{its result type is not an object pointer|"
"its result type is unrelated to its receiver type}1">;
def err_typecheck_arr_assign_self : Error<
"cannot assign to 'self' outside of a method in the init family">;
def err_typecheck_arr_assign_enumeration : Error<
"fast enumeration variables can't be modified in ARC by default; "
"declare the variable __strong to allow this">;
def warn_arc_non_pod_class_with_object_member : Warning<
"%0 cannot be shared between ARC and non-ARC "
"code; add a copy constructor, a copy assignment operator, and a destructor "
"to make it ABI-compatible">, InGroup<AutomaticReferenceCountingABI>,
DefaultIgnore;
def warn_arc_retained_assign : Warning<
"cannot assign retained object to %select{weak|unsafe_unretained}0 variable">;
def warn_arc_trivial_member_function_with_object_member : Warning<
"%0 cannot be shared between ARC and non-ARC "
"code; add a non-trivial %select{copy constructor|copy assignment operator|"
"destructor}1 to make it ABI-compatible">,
InGroup<AutomaticReferenceCountingABI>, DefaultIgnore;
def err_arc_new_array_without_lifetime : Error<
"'new' cannot allocate an array of %0 with no explicit lifetime">;
def warn_err_new_delete_object_array : Warning<
"%select{allocating|destroying}0 an array of %1; this array must not "
"%select{be deleted in|have been allocated from}0 non-ARC code">,
InGroup<AutomaticReferenceCountingABI>, DefaultIgnore;
def err_arc_autoreleasing_var : Error<
"%select{__block variables|global variables|fields|ivars}0 cannot have "
"__autoreleasing lifetime">;
def err_arc_thread_lifetime : Error<
"thread-local variable has non-trivial lifetime: type is %0">;
def err_arc_indirect_no_lifetime : Error<
"%select{pointer|reference}1 to non-const type %0 with no explicit lifetime">,
InGroup<AutomaticReferenceCounting>;
def err_arc_array_param_no_lifetime : Error<
"must explicitly describe intended lifetime of an object array parameter">;
def err_arc_pseudo_dtor_inconstant_quals : Error<
"pseudo-destructor destroys object of type %0 with inconsistently-qualified "
"type %1">;
def err_arc_init_method_unrelated_result_type : Error<
"init methods must return a type related to the receiver type">;
def err_arc_nonlocal_writeback : Error<
"passing address of %select{non-local|non-scalar}0 object to "
"__autoreleasing parameter for write-back">;
def err_arc_method_not_found : Error<
"no known %select{instance|class}1 method for selector %0">;
def err_arc_receiver_forward_class : Error<
"receiver %0 for class message is a forward declaration">;
def err_arc_may_not_respond : Error<
"receiver type %0 for instance message does not declare a method with "
"selector %1">;
def err_arc_receiver_forward_instance : Error<
"receiver type %0 for instance message is a forward declaration">;
def err_arc_multiple_method_decl : Error<
"multiple methods named %0 found with mismatched result, "
"parameter type or attributes">;
def warn_arc_retain_cycle : Warning<
"capturing %0 strongly in this block is likely to lead to a retain cycle">,
InGroup<DiagGroup<"retain-cycles">>;
def note_arc_retain_cycle_owner : Note<
"block will be retained by %select{the captured object|an object strongly "
"retained by the captured object}0">;
def note_nontrivial_objc_lifetime : Note<
"because type %0 has %select{no|no|__strong|__weak|__autoreleasing}1 "
"lifetime">;
def warn_arc_object_memaccess : Warning<
"%select{destination for|source of}0 this %1 call is a pointer to "
"lifetime-qualified type %2">, InGroup<DiagGroup<"non-pod-memaccess">>;
def err_arc_strong_property_lifetime : Error<
"existing ivar %1 for strong property %0 may not be "
"%select{|__unsafe_unretained||__weak}2">;
def err_arc_assign_property_lifetime : Error<
"existing ivar %1 for unsafe_unretained property %0 must be __unsafe_unretained">;
def err_arc_inconsistent_property_lifetime : Error<
"%select{strong|weak|unsafe_unretained}1 property %0 may not also be "
"declared %select{|__unsafe_unretained|__strong|__weak|__autoreleasing}2">;
def err_arc_atomic_lifetime : Error<
"cannot perform atomic operation on a pointer to type %0: type has "
"non-trivial lifetime">;
def err_arc_bridge_cast_incompatible : Error<
"incompatible types casting %0 to %1 with a %select{__bridge|"
"__bridge_transfer|__bridge_retained}2 cast">;
def err_arc_bridge_cast_wrong_kind : Error<
"cast of %select{Objective-C|block|C}0 pointer type %1 to "
"%select{Objective-C|block|C}2 pointer type %3 cannot use %select{__bridge|"
"__bridge_transfer|__bridge_retained}4">;
def err_arc_cast_requires_bridge : Error<
"cast of %select{Objective-C|block|C}0 pointer type %1 to "
"%select{Objective-C|block|C}2 pointer type %3 requires a bridged cast">;
def note_arc_bridge : Note<
"use __bridge to convert directly (no change in ownership)">;
def note_arc_bridge_transfer : Note<
"use __bridge_transfer to transfer ownership of a +1 %0 into ARC">;
def note_arc_bridge_retained : Note<
"use __bridge_retained to make an ARC object available as a +1 %0">;
} // ARC category name
def err_flexible_array_init_needs_braces : Error<
"flexible array requires brace-enclosed initializer">;
def err_illegal_decl_array_of_functions : Error<
@ -3337,6 +3510,15 @@ def err_typecheck_incompatible_address_space : Error<
"|sending %0 to parameter of type %1"
"|casting %0 to type %1}2"
" changes address space of pointer">;
def err_typecheck_incompatible_lifetime : Error<
"%select{assigning %1 to %0"
"|passing %0 to parameter of type %1"
"|returning %0 from a function with result type %1"
"|converting %0 to type %1"
"|initializing %0 with an expression of type %1"
"|sending %0 to parameter of type %1"
"|casting %0 to type %1}2"
" changes retain/release properties of pointer">;
def err_typecheck_convert_ambiguous : Error<
"ambiguity in initializing value of type %0 with initializer of type %1">;
def err_typecheck_comparison_of_distinct_blocks : Error<

View File

@ -130,6 +130,10 @@ public:
unsigned DefaultFPContract : 1; // Default setting for FP_CONTRACT
// FIXME: This is just a temporary option, for testing purposes.
unsigned NoBitFieldTypeAlign : 1;
unsigned ObjCAutoRefCount : 1; // Objective C automated reference counting
unsigned ObjCNoAutoRefCountRuntime : 1; // ARC w/o extra runtime support
unsigned ObjCInferRelatedReturnType : 1; // Infer Objective-C related return
// types
unsigned FakeAddressSpaceMap : 1; // Use a fake address space map, for
// testing languages such as OpenCL.
@ -172,6 +176,8 @@ public:
Trigraphs = BCPLComment = Bool = DollarIdents = AsmPreprocessor = 0;
GNUMode = GNUKeywords = ImplicitInt = Digraphs = 0;
HexFloats = 0;
ObjCAutoRefCount = ObjCNoAutoRefCountRuntime = 0;
ObjCInferRelatedReturnType = 0;
GC = ObjC1 = ObjC2 = ObjCNonFragileABI = ObjCNonFragileABI2 = 0;
AppleKext = 0;
ObjCDefaultSynthProperties = 0;

View File

@ -37,6 +37,7 @@ def ObjCAtFinallyStmt : Stmt;
def ObjCAtThrowStmt : Stmt;
def ObjCAtSynchronizedStmt : Stmt;
def ObjCForCollectionStmt : Stmt;
def ObjCAutoreleasePoolStmt : Stmt;
// C++ statments
def CXXCatchStmt : Stmt;
@ -130,6 +131,10 @@ def ObjCProtocolExpr : DStmt<Expr>;
def ObjCIvarRefExpr : DStmt<Expr>;
def ObjCPropertyRefExpr : DStmt<Expr>;
def ObjCIsaExpr : DStmt<Expr>;
def ObjCIndirectCopyRestoreExpr : DStmt<Expr>;
// Obj-C ARC Expressions.
def ObjCBridgedCastExpr : DStmt<ExplicitCastExpr>;
// CUDA Expressions.
def CUDAKernelCallExpr : DStmt<CallExpr>;

View File

@ -422,6 +422,11 @@ KEYWORD(__pascal , KEYALL)
KEYWORD(__vector , KEYALTIVEC)
KEYWORD(__pixel , KEYALTIVEC)
// Objective-C ARC keywords.
KEYWORD(__bridge , KEYARC)
KEYWORD(__bridge_transfer , KEYARC)
KEYWORD(__bridge_retained , KEYARC)
// Alternate spelling for various tokens. There are GCC extensions in all
// languages, but should not be disabled in strict conformance mode.
ALIAS("__alignof__" , __alignof , KEYALL)
@ -507,6 +512,7 @@ OBJC1_AT_KEYWORD(try)
OBJC1_AT_KEYWORD(catch)
OBJC1_AT_KEYWORD(finally)
OBJC1_AT_KEYWORD(synchronized)
OBJC1_AT_KEYWORD(autoreleasepool)
OBJC2_AT_KEYWORD(property)
OBJC2_AT_KEYWORD(package)

View File

@ -383,6 +383,13 @@ def create_module : Flag<"-create-module">,
HelpText<"Create a module definition file">;
}
def arcmt_check : Flag<"-arcmt-check">,
HelpText<"Check for ARC migration issues that need manual handling">;
def arcmt_modify : Flag<"-arcmt-modify">,
HelpText<"Apply modifications to files to conform to ARC">;
def arcmt_modify_in_memory : Flag<"-arcmt-modify-in-memory">,
HelpText<"Apply ARC conforming modifications & compile using memory buffers">;
def import_module : Separate<"-import-module">,
HelpText<"Import a module definition file">;
@ -479,6 +486,14 @@ def fconstant_string_class : Separate<"-fconstant-string-class">,
HelpText<"Specify the class to use for constant Objective-C string objects.">;
def fno_constant_cfstrings : Flag<"-fno-constant-cfstrings">,
HelpText<"Enable creation of CodeFoundation-type constant strings">;
def fobjc_arc : Flag<"-fobjc-arc">,
HelpText<"Synthesize retain and release calls for Objective-C pointers">;
def fobjc_arc_cxxlib_EQ : Joined<"-fobjc-arc-cxxlib=">,
HelpText<"Objective-C++ Automatic Reference Counting standard library kind">;
def fobjc_no_arc_runtime : Flag<"-fobjc-no-arc-runtime">,
HelpText<"Implement -fobjc-arc without any extra runtime support">;
def fobjc_arc_exceptions : Flag<"-fobjc-arc-exceptions">,
HelpText<"Use EH-safe code when synthesizing retains and releases in -fobjc-arc">;
def fobjc_gc : Flag<"-fobjc-gc">,
HelpText<"Enable Objective-C garbage collection">;
def fobjc_gc_only : Flag<"-fobjc-gc-only">,

View File

@ -112,6 +112,13 @@ def ccc_print_phases : Flag<"-ccc-print-phases">, CCCDebugOpt,
def ccc_print_bindings : Flag<"-ccc-print-bindings">, CCCDebugOpt,
HelpText<"Show bindings of tools to actions">;
def ccc_arrmt_check : Flag<"-ccc-arrmt-check">, CCCDriverOpt,
HelpText<"Check for ARC migration issues that need manual handling">;
def ccc_arrmt_modify : Flag<"-ccc-arrmt-modify">, CCCDriverOpt,
HelpText<"Apply modifications to files to conform to ARC">;
def ccc_arrmt_modify_in_memory : Flag<"-ccc-arrmt-modify-in-memory">,
HelpText<"Apply ARC conforming modifications & compile using memory buffers">;
// Make sure all other -ccc- options are rejected.
def ccc_ : Joined<"-ccc-">, Group<ccc_Group>, Flags<[Unsupported]>;
@ -382,6 +389,10 @@ def fno_verbose_asm : Flag<"-fno-verbose-asm">, Group<f_Group>;
def fno_working_directory : Flag<"-fno-working-directory">, Group<f_Group>;
def fno_wrapv : Flag<"-fno-wrapv">, Group<f_Group>;
def fno_zero_initialized_in_bss : Flag<"-fno-zero-initialized-in-bss">, Group<f_Group>;
def fobjc_arc : Flag<"-fobjc-arc">, Group<f_Group>;
def fno_objc_arc : Flag<"-fno-objc-arc">, Group<f_Group>;
def fobjc_arc_exceptions : Flag<"-fobjc-arc-exceptions">, Group<f_Group>;
def fno_objc_arc_exceptions : Flag<"-fno-objc-arc-exceptions">, Group<f_Group>;
def fobjc_atdefs : Flag<"-fobjc-atdefs">, Group<clang_ignored_f_Group>;
def fobjc_call_cxx_cdtors : Flag<"-fobjc-call-cxx-cdtors">, Group<clang_ignored_f_Group>;
def fobjc_default_synthesize_properties :
@ -392,6 +403,10 @@ def fobjc_gc_only : Flag<"-fobjc-gc-only">, Group<f_Group>;
def fobjc_gc : Flag<"-fobjc-gc">, Group<f_Group>;
def fobjc_legacy_dispatch : Flag<"-fobjc-legacy-dispatch">, Group<f_Group>;
def fobjc_new_property : Flag<"-fobjc-new-property">, Group<clang_ignored_f_Group>;
def fobjc_infer_related_result_type : Flag<"-fobjc-infer-related-result-type">,
Group<f_Group>;
def fno_objc_infer_related_result_type : Flag<
"-fno-objc-infer-related-result-type">, Group<f_Group>;
// Objective-C ABI options.
def fobjc_abi_version_EQ : Joined<"-fobjc-abi-version=">, Group<f_Group>;

View File

@ -166,6 +166,9 @@ public:
/// UseSjLjExceptions - Does this tool chain use SjLj exceptions.
virtual bool UseSjLjExceptions() const { return false; }
/// HasARCRuntime - Does this tool chain provide a specialized ARC runtime.
virtual bool HasARCRuntime() const { return false; }
/// ComputeLLVMTriple - Return the LLVM target triple to use, after taking
/// command line arguments into account.
virtual std::string ComputeLLVMTriple(const ArgList &Args) const;
@ -184,7 +187,8 @@ public:
/// AddClangCXXStdlibIncludeArgs - Add the clang -cc1 level arguments to set
/// the include paths to use for the given C++ standard library type.
virtual void AddClangCXXStdlibIncludeArgs(const ArgList &Args,
ArgStringList &CmdArgs) const;
ArgStringList &CmdArgs,
bool ObjCXXAutoRefCount) const;
/// AddCXXStdlibLibArgs - Add the system specific linker arguments to use
/// for the given C++ standard library type.

View File

@ -36,6 +36,7 @@ public:
};
unsigned AsmVerbose : 1; /// -dA, -fverbose-asm.
unsigned ObjCAutoRefCountExceptions : 1; /// Whether ARC should be EH-safe.
unsigned CXAAtExit : 1; /// Use __cxa_atexit for calling destructors.
unsigned CXXCtorDtorAliases: 1; /// Emit complete ctors/dtors as linker
/// aliases to base ctors when possible.
@ -133,6 +134,7 @@ public:
public:
CodeGenOptions() {
AsmVerbose = 0;
ObjCAutoRefCountExceptions = 0;
CXAAtExit = 1;
CXXCtorDtorAliases = 0;
DataSections = 0;

View File

@ -77,6 +77,13 @@ public:
unsigned FixWhatYouCan : 1; ///< Apply fixes even if there are
/// unfixable errors.
enum {
ARCMT_None,
ARCMT_Check,
ARCMT_Modify,
ARCMT_ModifyInMemory
} ARCMTAction;
/// The input files and their types.
std::vector<std::pair<InputKind, std::string> > Inputs;
@ -131,6 +138,7 @@ public:
ShowStats = 0;
ShowTimers = 0;
ShowVersion = 0;
ARCMTAction = ARCMT_None;
}
/// getInputKindForExtension - Return the appropriate input kind for a file

View File

@ -26,6 +26,15 @@ namespace clang {
class Preprocessor;
class LangOptions;
/// \brief Enumerate the kinds of standard library that
enum ObjCXXARCStandardLibraryKind {
ARCXX_nolib,
/// \brief libc++
ARCXX_libcxx,
/// \brief libstdc++
ARCXX_libstdcxx
};
/// PreprocessorOptions - This class is used for passing the various options
/// used in preprocessor initialization to InitializePreprocessor().
class PreprocessorOptions {
@ -104,6 +113,11 @@ public:
/// compiler invocation and its buffers will be reused.
bool RetainRemappedFileBuffers;
/// \brief The Objective-C++ ARC standard library that we should support,
/// by providing appropriate definitions to retrofit the standard library
/// with support for lifetime-qualified pointers.
ObjCXXARCStandardLibraryKind ObjCXXARCStandardLibrary;
typedef std::vector<std::pair<std::string, std::string> >::iterator
remapped_file_iterator;
typedef std::vector<std::pair<std::string, std::string> >::const_iterator
@ -145,7 +159,8 @@ public:
DumpDeserializedPCHDecls(false),
PrecompiledPreambleBytes(0, true),
RemappedFilesKeepOriginalName(true),
RetainRemappedFileBuffers(false) { }
RetainRemappedFileBuffers(false),
ObjCXXARCStandardLibrary(ARCXX_nolib) { }
void addMacroDef(llvm::StringRef Name) {
Macros.push_back(std::make_pair(Name, false));

View File

@ -19,6 +19,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/Support/raw_ostream.h"
#include "clang/Basic/Diagnostic.h"
namespace llvm {
class Triple;

View File

@ -1375,6 +1375,7 @@ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
StmtResult ParseObjCTryStmt(SourceLocation atLoc);
StmtResult ParseObjCThrowStmt(SourceLocation atLoc);
StmtResult ParseObjCSynchronizedStmt(SourceLocation atLoc);
StmtResult ParseObjCAutoreleasePoolStmt(SourceLocation atLoc);
//===--------------------------------------------------------------------===//
@ -1616,7 +1617,8 @@ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
TypeResult ParseTypeName(SourceRange *Range = 0,
Declarator::TheContext Context
= Declarator::TypeNameContext);
= Declarator::TypeNameContext,
ObjCDeclSpec *objcQuals = 0);
void ParseBlockId();
void ProhibitAttributes(ParsedAttributesWithRange &attrs) {

View File

@ -183,8 +183,11 @@ public:
/// InsertText - Insert the specified string at the specified location in the
/// original buffer. This method returns true (and does nothing) if the input
/// location was not rewritable, false otherwise.
///
/// \param indentNewLines if true new lines in the string are indented
/// using the indentation of the source line in position \arg Loc.
bool InsertText(SourceLocation Loc, llvm::StringRef Str,
bool InsertAfter = true);
bool InsertAfter = true, bool indentNewLines = false);
/// InsertTextAfter - Insert the specified string at the specified location in
/// the original buffer. This method returns true (and does nothing) if

View File

@ -198,6 +198,7 @@ public:
AT_objc_method_family,
AT_cf_returns_not_retained, // Clang-specific.
AT_cf_returns_retained, // Clang-specific.
AT_cf_returns_autoreleased, // Clang-specific.
AT_ns_returns_not_retained, // Clang-specific.
AT_ns_returns_retained, // Clang-specific.
AT_ns_returns_autoreleased, // Clang-specific.
@ -205,6 +206,8 @@ public:
AT_ns_consumed, // Clang-specific.
AT_ns_consumes_self, // Clang-specific.
AT_objc_gc,
AT_objc_lifetime, // Clang-specific.
AT_objc_precise_lifetime, // Clang-specific.
AT_opencl_image_access, // OpenCL-specific.
AT_opencl_kernel_function, // OpenCL-specific.
AT_overloadable, // Clang-specific.

View File

@ -40,6 +40,7 @@ namespace clang {
class NamespaceDecl;
class NestedNameSpecifier;
class NestedNameSpecifierLoc;
class ObjCDeclSpec;
class Preprocessor;
class Declarator;
struct TemplateIdAnnotation;
@ -344,6 +345,8 @@ private:
void SaveWrittenBuiltinSpecs();
void SaveStorageSpecifierAsWritten();
ObjCDeclSpec *ObjCQualifiers;
static bool isTypeRep(TST T) {
return (T == TST_typename || T == TST_typeofType ||
T == TST_underlyingType);
@ -383,7 +386,8 @@ public:
ProtocolQualifiers(0),
NumProtocolQualifiers(0),
ProtocolLocs(0),
writtenBS() {
writtenBS(),
ObjCQualifiers(0) {
}
~DeclSpec() {
delete [] ProtocolQualifiers;
@ -653,6 +657,9 @@ public:
return writtenBS;
}
ObjCDeclSpec *getObjCQualifiers() const { return ObjCQualifiers; }
void setObjCQualifiers(ObjCDeclSpec *quals) { ObjCQualifiers = quals; }
/// isMissingDeclaratorOk - This checks if this DeclSpec can stand alone,
/// without a Declarator. Only tag declspecs can stand alone.
bool isMissingDeclaratorOk();
@ -689,7 +696,10 @@ public:
DQ_PR_copy = 0x20,
DQ_PR_nonatomic = 0x40,
DQ_PR_setter = 0x80,
DQ_PR_atomic = 0x100
DQ_PR_atomic = 0x100,
DQ_PR_weak = 0x200,
DQ_PR_strong = 0x400,
DQ_PR_unsafe_unretained = 0x800
};
@ -723,7 +733,7 @@ private:
ObjCDeclQualifier objcDeclQualifier : 6;
// NOTE: VC++ treats enums as signed, avoid using ObjCPropertyAttributeKind
unsigned PropertyAttributes : 9;
unsigned PropertyAttributes : 12;
IdentifierInfo *GetterName; // getter name of NULL if no getter
IdentifierInfo *SetterName; // setter name of NULL if no setter
};

View File

@ -112,7 +112,7 @@ private:
/// the complete parsing of the current declaration.
class DelayedDiagnostic {
public:
enum DDKind { Deprecation, Access };
enum DDKind { Deprecation, Access, ForbiddenType };
unsigned char Kind; // actually a DDKind
bool Triggered;
@ -135,6 +135,20 @@ public:
return DD;
}
static DelayedDiagnostic makeForbiddenType(SourceLocation loc,
unsigned diagnostic,
QualType type,
unsigned argument) {
DelayedDiagnostic DD;
DD.Kind = ForbiddenType;
DD.Triggered = false;
DD.Loc = loc;
DD.ForbiddenTypeData.Diagnostic = diagnostic;
DD.ForbiddenTypeData.OperandType = type.getAsOpaquePtr();
DD.ForbiddenTypeData.Argument = argument;
return DD;
}
AccessedEntity &getAccessData() {
assert(Kind == Access && "Not an access diagnostic.");
return *reinterpret_cast<AccessedEntity*>(AccessData);
@ -155,6 +169,25 @@ public:
DeprecationData.MessageLen);
}
/// The diagnostic ID to emit. Used like so:
/// Diag(diag.Loc, diag.getForbiddenTypeDiagnostic())
/// << diag.getForbiddenTypeOperand()
/// << diag.getForbiddenTypeArgument();
unsigned getForbiddenTypeDiagnostic() const {
assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
return ForbiddenTypeData.Diagnostic;
}
unsigned getForbiddenTypeArgument() const {
assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
return ForbiddenTypeData.Argument;
}
QualType getForbiddenTypeOperand() const {
assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
return QualType::getFromOpaquePtr(ForbiddenTypeData.OperandType);
}
private:
union {
/// Deprecation.
@ -164,6 +197,12 @@ private:
size_t MessageLen;
} DeprecationData;
struct {
unsigned Diagnostic;
unsigned Argument;
void *OperandType;
} ForbiddenTypeData;
/// Access control.
char AccessData[sizeof(AccessedEntity)];
};

View File

@ -86,9 +86,13 @@ private:
QualType Type;
union {
/// \brief When Kind == EK_Variable, EK_Parameter, or EK_Member,
/// the VarDecl, ParmVarDecl, or FieldDecl, respectively.
/// \brief When Kind == EK_Variable or EK_Member, the VarDecl or
/// FieldDecl, respectively.
DeclaratorDecl *VariableOrMember;
/// \brief When Kind == EK_Parameter, the ParmVarDecl, with the
/// low bit indicating whether the parameter is "consumed".
uintptr_t Parameter;
/// \brief When Kind == EK_Temporary, the type source information for
/// the temporary.
@ -123,11 +127,6 @@ private:
: Kind(EK_Variable), Parent(0), Type(Var->getType()),
VariableOrMember(Var) { }
/// \brief Create the initialization entity for a parameter.
InitializedEntity(ParmVarDecl *Parm)
: Kind(EK_Parameter), Parent(0), Type(Parm->getType().getUnqualifiedType()),
VariableOrMember(Parm) { }
/// \brief Create the initialization entity for the result of a
/// function, throwing an object, performing an explicit cast, or
/// initializing a parameter for which there is no declaration.
@ -157,20 +156,28 @@ public:
/// \brief Create the initialization entity for a parameter.
static InitializedEntity InitializeParameter(ASTContext &Context,
ParmVarDecl *Parm) {
InitializedEntity Res(Parm);
Res.Type = Context.getVariableArrayDecayedType(Res.Type);
return Res;
bool Consumed = (Context.getLangOptions().ObjCAutoRefCount &&
Parm->hasAttr<NSConsumedAttr>());
InitializedEntity Entity;
Entity.Kind = EK_Parameter;
Entity.Type = Context.getVariableArrayDecayedType(
Parm->getType().getUnqualifiedType());
Entity.Parent = 0;
Entity.Parameter = (Consumed | reinterpret_cast<uintptr_t>(Parm));
return Entity;
}
/// \brief Create the initialization entity for a parameter that is
/// only known by its type.
static InitializedEntity InitializeParameter(ASTContext &Context,
QualType Type) {
QualType Type,
bool Consumed) {
InitializedEntity Entity;
Entity.Kind = EK_Parameter;
Entity.Type = Context.getVariableArrayDecayedType(Type);
Entity.Parent = 0;
Entity.VariableOrMember = 0;
Entity.Parameter = (Consumed);
return Entity;
}
@ -268,6 +275,13 @@ public:
/// \brief Determine whether this initialization allows the named return
/// value optimization, which also applies to thrown objects.
bool allowsNRVO() const;
/// \brief Determine whether this initialization consumes the
/// parameter.
bool isParameterConsumed() const {
assert(getKind() == EK_Parameter && "Not a parameter");
return (Parameter & 1);
}
/// \brief Retrieve the base specifier.
CXXBaseSpecifier *getBaseSpecifier() const {
@ -287,7 +301,7 @@ public:
assert(getKind() == EK_Result && "No 'return' location!");
return SourceLocation::getFromRawEncoding(LocAndNRVO.Location);
}
/// \brief Determine the location of the 'throw' keyword when initializing
/// an exception object.
SourceLocation getThrowLoc() const {
@ -325,8 +339,10 @@ private:
SIK_Value = IK_Value, ///< Value initialization
SIK_ImplicitValue, ///< Implicit value initialization
SIK_DirectCast, ///< Direct initialization due to a cast
/// \brief Direct initialization due to a C-style or functional cast.
SIK_DirectCStyleOrFunctionalCast
/// \brief Direct initialization due to a C-style cast.
SIK_DirectCStyleCast,
/// \brief Direct initialization due to a functional-style cast.
SIK_DirectFunctionalCast
};
/// \brief The kind of initialization being performed.
@ -352,15 +368,29 @@ public:
return InitializationKind(SIK_Direct, InitLoc, LParenLoc, RParenLoc);
}
/// \brief Create a direct initialization due to a cast.
static InitializationKind CreateCast(SourceRange TypeRange,
bool IsCStyleCast) {
return InitializationKind(IsCStyleCast? SIK_DirectCStyleOrFunctionalCast
: SIK_DirectCast,
/// \brief Create a direct initialization due to a cast that isn't a C-style
/// or functional cast.
static InitializationKind CreateCast(SourceRange TypeRange) {
return InitializationKind(SIK_DirectCast,
TypeRange.getBegin(), TypeRange.getBegin(),
TypeRange.getEnd());
}
/// \brief Create a direct initialization for a C-style cast.
static InitializationKind CreateCStyleCast(SourceLocation StartLoc,
SourceRange TypeRange) {
return InitializationKind(SIK_DirectCStyleCast,
StartLoc, TypeRange.getBegin(),
TypeRange.getEnd());
}
/// \brief Create a direct initialization for a functional cast.
static InitializationKind CreateFunctionalCast(SourceRange TypeRange) {
return InitializationKind(SIK_DirectFunctionalCast,
TypeRange.getBegin(), TypeRange.getBegin(),
TypeRange.getEnd());
}
/// \brief Create a copy initialization.
static InitializationKind CreateCopy(SourceLocation InitLoc,
SourceLocation EqualLoc) {
@ -393,12 +423,24 @@ public:
/// \brief Determine whether this initialization is an explicit cast.
bool isExplicitCast() const {
return Kind == SIK_DirectCast || Kind == SIK_DirectCStyleOrFunctionalCast;
return Kind == SIK_DirectCast ||
Kind == SIK_DirectCStyleCast ||
Kind == SIK_DirectFunctionalCast;
}
/// \brief Determine whether this initialization is a C-style cast.
bool isCStyleOrFunctionalCast() const {
return Kind == SIK_DirectCStyleOrFunctionalCast;
return Kind == SIK_DirectCStyleCast || Kind == SIK_DirectFunctionalCast;
}
/// brief Determine whether this is a C-style cast.
bool isCStyleCast() const {
return Kind == SIK_DirectCStyleCast;
}
/// brief Determine whether this is a functional-style cast.
bool isFunctionalCast() const {
return Kind == SIK_DirectFunctionalCast;
}
/// \brief Determine whether this initialization is an implicit
@ -500,7 +542,13 @@ public:
SK_ObjCObjectConversion,
/// \brief Array initialization (from an array rvalue).
/// This is a GNU C extension.
SK_ArrayInit
SK_ArrayInit,
/// \brief Pass an object by indirect copy-and-restore.
SK_PassByIndirectCopyRestore,
/// \brief Pass an object by indirect restore.
SK_PassByIndirectRestore,
/// \brief Produce an Objective-C object pointer.
SK_ProduceObjCObject
};
/// \brief A single step in the initialization sequence.
@ -774,6 +822,13 @@ public:
/// \brief Add an array initialization step.
void AddArrayInitStep(QualType T);
/// \brief Add a step to pass an object by indirect copy-restore.
void AddPassByIndirectCopyRestoreStep(QualType T, bool shouldCopy);
/// \brief Add a step to "produce" an Objective-C object (by
/// retaining it).
void AddProduceObjCObjectStep(QualType T);
/// \brief Note that this initialization sequence failed.
void SetFailed(FailureKind Failure) {
SequenceKind = FailedSequence;

View File

@ -77,6 +77,7 @@ namespace clang {
ICK_Complex_Real, ///< Complex-real conversions (C99 6.3.1.7)
ICK_Block_Pointer_Conversion, ///< Block Pointer conversions
ICK_TransparentUnionConversion, /// Transparent Union Conversions
ICK_Writeback_Conversion, ///< Objective-C ARC writeback conversion
ICK_Num_Conversion_Kinds ///< The number of conversion kinds
};
@ -100,10 +101,11 @@ namespace clang {
/// 13.3.3.1.1) and are listed such that better conversion ranks
/// have smaller values.
enum ImplicitConversionRank {
ICR_Exact_Match = 0, ///< Exact Match
ICR_Promotion, ///< Promotion
ICR_Conversion, ///< Conversion
ICR_Complex_Real_Conversion ///< Complex <-> Real conversion
ICR_Exact_Match = 0, ///< Exact Match
ICR_Promotion, ///< Promotion
ICR_Conversion, ///< Conversion
ICR_Complex_Real_Conversion, ///< Complex <-> Real conversion
ICR_Writeback_Conversion ///< ObjC ARC writeback conversion
};
ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind);
@ -137,6 +139,10 @@ namespace clang {
/// (C++ 4.2p2).
unsigned DeprecatedStringLiteralToCharPtr : 1;
/// \brief Whether the qualification conversion involves a change in the
/// Objective-C lifetime (for automatic reference counting).
unsigned QualificationIncludesObjCLifetime : 1;
/// IncompatibleObjC - Whether this is an Objective-C conversion
/// that we should warn about (if we actually use it).
unsigned IncompatibleObjC : 1;
@ -163,6 +169,10 @@ namespace clang {
/// non-static member function without a ref-qualifier.
unsigned BindsImplicitObjectArgumentWithoutRefQualifier : 1;
/// \brief Whether this binds a reference to an object with a different
/// Objective-C lifetime qualifier.
unsigned ObjCLifetimeConversionBinding : 1;
/// FromType - The type that this conversion is converting
/// from. This is an opaque pointer that can be translated into a
/// QualType.

View File

@ -108,6 +108,7 @@ namespace clang {
class ObjCInterfaceDecl;
class ObjCIvarDecl;
template <class T> class ObjCList;
class ObjCMessageExpr;
class ObjCMethodDecl;
class ObjCPropertyDecl;
class ObjCProtocolDecl;
@ -247,6 +248,10 @@ public:
/// VisContext - Manages the stack for #pragma GCC visibility.
void *VisContext; // Really a "PragmaVisStack*"
/// ExprNeedsCleanups - True if the current evaluation context
/// requires cleanups to be run at its conclusion.
bool ExprNeedsCleanups;
/// \brief Stack containing information about each of the nested
/// function, block, and method scopes that are currently active.
///
@ -555,6 +560,9 @@ public:
/// \brief The expression evaluation context.
ExpressionEvaluationContext Context;
/// \brief Whether the enclosing context needed a cleanup.
bool ParentNeedsCleanups;
/// \brief The number of temporaries that were active when we
/// entered this expression evaluation context.
unsigned NumTemporaries;
@ -573,8 +581,10 @@ public:
PotentiallyEmittedDiagnostics *PotentiallyDiagnosed;
ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context,
unsigned NumTemporaries)
: Context(Context), NumTemporaries(NumTemporaries),
unsigned NumTemporaries,
bool ParentNeedsCleanups)
: Context(Context), ParentNeedsCleanups(ParentNeedsCleanups),
NumTemporaries(NumTemporaries),
PotentiallyReferenced(0), PotentiallyDiagnosed(0) { }
void addReferencedDecl(SourceLocation Loc, Decl *Decl) {
@ -766,7 +776,7 @@ public:
return FunctionScopes.back();
}
bool hasAnyErrorsInThisFunction() const;
bool hasAnyUnrecoverableErrorsInThisFunction() const;
/// \brief Retrieve the current block, if any.
sema::BlockScopeInfo *getCurBlock();
@ -838,7 +848,7 @@ public:
const FunctionProtoType *Source, SourceLocation SourceLoc);
TypeResult ActOnTypeName(Scope *S, Declarator &D);
bool RequireCompleteType(SourceLocation Loc, QualType T,
const PartialDiagnostic &PD,
std::pair<SourceLocation, PartialDiagnostic> Note);
@ -1305,13 +1315,13 @@ public:
bool IsForUsingDecl);
bool IsOverload(FunctionDecl *New, FunctionDecl *Old, bool IsForUsingDecl);
bool TryImplicitConversion(InitializationSequence &Sequence,
const InitializedEntity &Entity,
Expr *From,
bool SuppressUserConversions,
bool AllowExplicit,
bool InOverloadResolution,
bool CStyle);
ImplicitConversionSequence
TryImplicitConversion(Expr *From, QualType ToType,
bool SuppressUserConversions,
bool AllowExplicit,
bool InOverloadResolution,
bool CStyle,
bool AllowObjCWritebackConversion);
bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType);
bool IsFloatingPointPromotion(QualType FromType, QualType ToType);
@ -1321,6 +1331,8 @@ public:
QualType& ConvertedType, bool &IncompatibleObjC);
bool isObjCPointerConversion(QualType FromType, QualType ToType,
QualType& ConvertedType, bool &IncompatibleObjC);
bool isObjCWritebackConversion(QualType FromType, QualType ToType,
QualType &ConvertedType);
bool IsBlockPointerConversion(QualType FromType, QualType ToType,
QualType& ConvertedType);
bool FunctionArgTypesAreEqual(const FunctionProtoType *OldType,
@ -1338,7 +1350,7 @@ public:
CXXCastPath &BasePath,
bool IgnoreBaseAccess);
bool IsQualificationConversion(QualType FromType, QualType ToType,
bool CStyle);
bool CStyle, bool &ObjCLifetimeConversion);
bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType);
@ -1853,14 +1865,20 @@ public:
void AtomicPropertySetterGetterRules(ObjCImplDecl* IMPDecl,
ObjCContainerDecl* IDecl);
void DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D);
void DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, ObjCInterfaceDecl *SID);
enum MethodMatchStrategy {
MMS_loose,
MMS_strict
};
/// MatchTwoMethodDeclarations - Checks if two methods' type match and returns
/// true, or false, accordingly.
bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method,
const ObjCMethodDecl *PrevMethod,
bool matchBasedOnSizeAndAlignment = false,
bool matchBasedOnStrictEqulity = false);
MethodMatchStrategy strategy = MMS_strict);
/// MatchAllMethodDeclarations - Check methods declaraed in interface or
/// or protocol against those declared in their implementations.
@ -2073,10 +2091,13 @@ public:
Expr *SynchExpr,
Stmt *SynchBody);
StmtResult ActOnObjCAutoreleasePoolStmt(SourceLocation AtLoc, Stmt *Body);
VarDecl *BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo,
SourceLocation StartLoc,
SourceLocation IdLoc,
IdentifierInfo *Id);
Decl *ActOnExceptionDeclarator(Scope *S, Declarator &D);
StmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc,
@ -2130,6 +2151,9 @@ public:
void HandleDelayedDeprecationCheck(sema::DelayedDiagnostic &DD, Decl *Ctx);
bool makeUnavailableInSystemHeader(SourceLocation loc,
llvm::StringRef message);
//===--------------------------------------------------------------------===//
// Expression Parsing Callbacks: SemaExpr.cpp.
@ -2146,6 +2170,8 @@ public:
void PopExpressionEvaluationContext();
void DiscardCleanupsInEvaluationContext();
void MarkDeclarationReferenced(SourceLocation Loc, Decl *D);
void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T);
void MarkDeclarationsReferencedInExpr(Expr *E);
@ -4982,6 +5008,15 @@ public:
IdentifierInfo *PropertyIvar,
SourceLocation PropertyIvarLoc);
enum ObjCSpecialMethodKind {
OSMK_None,
OSMK_Alloc,
OSMK_New,
OSMK_Copy,
OSMK_RetainingInit,
OSMK_NonRetainingInit
};
struct ObjCArgInfo {
IdentifierInfo *Name;
SourceLocation NameLoc;
@ -5020,6 +5055,8 @@ public:
const ObjCObjectPointerType *OPT,
bool IsInstance);
bool inferObjCARCLifetime(ValueDecl *decl);
ExprResult
HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
Expr *BaseExpr,
@ -5098,6 +5135,22 @@ public:
SourceLocation RBracLoc,
MultiExprArg Args);
ExprResult BuildObjCBridgedCast(SourceLocation LParenLoc,
ObjCBridgeCastKind Kind,
SourceLocation BridgeKeywordLoc,
TypeSourceInfo *TSInfo,
Expr *SubExpr);
ExprResult ActOnObjCBridgedCast(Scope *S,
SourceLocation LParenLoc,
ObjCBridgeCastKind Kind,
SourceLocation BridgeKeywordLoc,
ParsedType Type,
SourceLocation RParenLoc,
Expr *SubExpr);
bool checkInitMethod(ObjCMethodDecl *method, QualType receiverTypeIfCall);
/// \brief Check whether the given new method is a valid override of the
/// given overridden method, and set any properties that should be inherited.
///
@ -5105,7 +5158,7 @@ public:
bool CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
const ObjCMethodDecl *Overridden,
bool IsImplementation);
/// \brief Check whether the given method overrides any methods in its class,
/// calling \c CheckObjCMethodOverride for each overridden method.
bool CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod, DeclContext *DC);
@ -5208,12 +5261,26 @@ public:
/// from the inner expression.
ExprValueKind CastCategory(Expr *E);
/// \brief The kind of conversion being performed.
enum CheckedConversionKind {
/// \brief An implicit conversion.
CCK_ImplicitConversion,
/// \brief A C-style cast.
CCK_CStyleCast,
/// \brief A functional-style cast.
CCK_FunctionalCast,
/// \brief A cast other than a C-style cast.
CCK_OtherCast
};
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit
/// cast. If there is already an implicit cast, merge into the existing one.
/// If isLvalue, the result of the cast is an lvalue.
ExprResult ImpCastExprToType(Expr *E, QualType Type, CastKind CK,
ExprValueKind VK = VK_RValue,
const CXXCastPath *BasePath = 0);
const CXXCastPath *BasePath = 0,
CheckedConversionKind CCK
= CCK_ImplicitConversion);
/// ScalarTypeToBooleanCastKind - Returns the cast kind corresponding
/// to the conversion from scalar type ScalarTy to the Boolean type.
@ -5393,11 +5460,12 @@ public:
ExprResult PerformImplicitConversion(Expr *From, QualType ToType,
const ImplicitConversionSequence& ICS,
AssignmentAction Action,
bool CStyle = false);
CheckedConversionKind CCK
= CCK_ImplicitConversion);
ExprResult PerformImplicitConversion(Expr *From, QualType ToType,
const StandardConversionSequence& SCS,
AssignmentAction Action,
bool CStyle);
CheckedConversionKind CCK);
/// the following "Check" methods will return a valid/converted QualType
/// or a null QualType (indicating an error diagnostic was issued).
@ -5494,12 +5562,14 @@ public:
ReferenceCompareResult CompareReferenceRelationship(SourceLocation Loc,
QualType T1, QualType T2,
bool &DerivedToBase,
bool &ObjCConversion);
bool &ObjCConversion,
bool &ObjCLifetimeConversion);
/// CheckCastTypes - Check type constraints for casting between types under
/// C semantics, or forward to CXXCheckCStyleCast in C++.
ExprResult CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *CastExpr,
CastKind &Kind, ExprValueKind &VK, CXXCastPath &BasePath,
ExprResult CheckCastTypes(SourceLocation CastStartLoc, SourceRange TyRange,
QualType CastTy, Expr *CastExpr, CastKind &Kind,
ExprValueKind &VK, CXXCastPath &BasePath,
bool FunctionalStyle = false);
ExprResult checkUnknownAnyCast(SourceRange TyRange, QualType castType,
@ -5526,6 +5596,20 @@ public:
ExprResult CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
Expr *CastExpr, CastKind &Kind,
CXXCastPath &BasePath, bool FunctionalStyle);
/// \brief Checks for invalid conversions and casts between
/// retainable pointers and other pointer kinds.
void CheckObjCARCConversion(SourceRange castRange, QualType castType,
Expr *op, CheckedConversionKind CCK);
/// checkRetainCycles - Check whether an Objective-C message send
/// might create an obvious retain cycle.
void checkRetainCycles(ObjCMessageExpr *msg);
void checkRetainCycles(Expr *receiver, Expr *argument);
/// checkWeakUnsafeAssigns - Check whether +1 expr is being assigned
/// to weak/__unsafe_unretained.
void checkUnsafeAssigns(SourceLocation Loc, QualType LHS, Expr *RHS);
/// CheckMessageArgumentTypes - Check types in an Obj-C message send.
/// \param Method - May be null.
@ -5544,7 +5628,7 @@ public:
QualType getMessageSendResultType(QualType ReceiverType,
ObjCMethodDecl *Method,
bool isClassMessage, bool isSuperMessage);
/// \brief If the given expression involves a message send to a method
/// with a related result type, emit a note describing what happened.
void EmitRelatedResultTypeNote(const Expr *E);

View File

@ -922,6 +922,8 @@ namespace clang {
EXPR_OBJC_MESSAGE_EXPR,
/// \brief An ObjCIsa Expr record.
EXPR_OBJC_ISA,
/// \breif An ObjCIndirectCopyRestoreExpr record.
EXPR_OBJC_INDIRECT_COPY_RESTORE,
/// \brief An ObjCForCollectionStmt record.
STMT_OBJC_FOR_COLLECTION,
@ -935,6 +937,8 @@ namespace clang {
STMT_OBJC_AT_SYNCHRONIZED,
/// \brief An ObjCAtThrowStmt record.
STMT_OBJC_AT_THROW,
/// \brief An ObjCAutoreleasePoolStmt record.
STMT_OBJC_AUTORELEASE_POOL,
// C++
@ -1002,11 +1006,13 @@ namespace clang {
EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK,// SubstNonTypeTemplateParmPackExpr
// CUDA
EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr
EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr
// OpenCL
EXPR_ASTYPE // An AsTypeExpr record.
EXPR_ASTYPE, // AsTypeExpr
// ARC
EXPR_OBJC_BRIDGED_CAST // ObjCBridgedCastExpr
};
/// \brief The kinds of designators that can occur in a

View File

@ -221,9 +221,9 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
DependentTemplateSpecializationTypes(this_()),
GlobalNestedNameSpecifier(0), IsInt128Installed(false),
CFConstantStringTypeDecl(0), NSConstantStringTypeDecl(0),
ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), jmp_bufDecl(0),
sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0),
cudaConfigureCallDecl(0),
ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0),
jmp_bufDecl(0), sigjmp_bufDecl(0), BlockDescriptorType(0),
BlockDescriptorExtendedType(0), cudaConfigureCallDecl(0),
NullTypeSourceInfo(QualType()),
SourceMgr(SM), LangOpts(LOpts), ABI(createCXXABI(t)),
AddrSpaceMap(getAddressSpaceMap(t, LOpts)), Target(t),
@ -2040,10 +2040,13 @@ ASTContext::getFunctionType(QualType ResultTy,
assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
}
// FunctionProtoType objects are allocated with extra bytes after them
// for two variable size arrays (for parameter and exception types) at the
// end of them. Instead of the exception types, there could be a noexcept
// expression and a context pointer.
// FunctionProtoType objects are allocated with extra bytes after
// them for three variable size arrays at the end:
// - parameter types
// - exception types
// - consumed-arguments flags
// Instead of the exception types, there could be a noexcept
// expression.
size_t Size = sizeof(FunctionProtoType) +
NumArgs * sizeof(QualType);
if (EPI.ExceptionSpecType == EST_Dynamic)
@ -2051,6 +2054,9 @@ ASTContext::getFunctionType(QualType ResultTy,
else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
Size += sizeof(Expr*);
}
if (EPI.ConsumedArguments)
Size += NumArgs * sizeof(bool);
FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment);
FunctionProtoType::ExtProtoInfo newEPI = EPI;
newEPI.ExtInfo = EPI.ExtInfo.withCallingConv(CallConv);
@ -2925,7 +2931,6 @@ CanQualType ASTContext::getCanonicalParamType(QualType T) const {
return CanQualType::CreateUnsafe(Result);
}
QualType ASTContext::getUnqualifiedArrayType(QualType type,
Qualifiers &quals) {
SplitQualType splitType = type.getSplitUnqualifiedType();
@ -3725,11 +3730,7 @@ void ASTContext::setBlockDescriptorExtendedType(QualType T) {
}
bool ASTContext::BlockRequiresCopying(QualType Ty) const {
if (Ty->isBlockPointerType())
return true;
if (isObjCNSObjectType(Ty))
return true;
if (Ty->isObjCObjectPointerType())
if (Ty->isObjCRetainableType())
return true;
if (getLangOptions().CPlusPlus) {
if (const RecordType *RT = Ty->getAs<RecordType>()) {
@ -4826,20 +4827,6 @@ CanQualType ASTContext::getFromTargetType(unsigned Type) const {
// Type Predicates.
//===----------------------------------------------------------------------===//
/// isObjCNSObjectType - Return true if this is an NSObject object using
/// NSObject attribute on a c-style pointer type.
/// FIXME - Make it work directly on types.
/// FIXME: Move to Type.
///
bool ASTContext::isObjCNSObjectType(QualType Ty) const {
if (const TypedefType *TDT = dyn_cast<TypedefType>(Ty)) {
if (TypedefNameDecl *TD = TDT->getDecl())
if (TD->getAttr<ObjCNSObjectAttr>())
return true;
}
return false;
}
/// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's
/// garbage collection attribute.
///
@ -5452,6 +5439,9 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
if (lbaseInfo.getRegParm() != rbaseInfo.getRegParm())
return QualType();
if (lbaseInfo.getProducesResult() != rbaseInfo.getProducesResult())
return QualType();
// It's noreturn if either type is.
// FIXME: some uses, e.g. conditional exprs, really want this to be 'both'.
bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn();
@ -5460,10 +5450,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
if (NoReturn != rbaseInfo.getNoReturn())
allRTypes = false;
FunctionType::ExtInfo einfo(NoReturn,
lbaseInfo.getHasRegParm(),
lbaseInfo.getRegParm(),
lbaseInfo.getCC());
FunctionType::ExtInfo einfo = lbaseInfo.withNoReturn(NoReturn);
if (lproto && rproto) { // two C99 style function prototypes
assert(!lproto->hasExceptionSpec() && !rproto->hasExceptionSpec() &&
@ -5584,7 +5571,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
// If any of these qualifiers are different, we have a type
// mismatch.
if (LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers() ||
LQuals.getAddressSpace() != RQuals.getAddressSpace())
LQuals.getAddressSpace() != RQuals.getAddressSpace() ||
LQuals.getObjCLifetime() != RQuals.getObjCLifetime())
return QualType();
// Exactly one GC qualifier difference is allowed: __strong is

View File

@ -228,6 +228,11 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
if (!BaseClassDecl->hasTrivialDestructor())
data().HasTrivialDestructor = false;
// A class has an Objective-C object member if... or any of its bases
// has an Objective-C object member.
if (BaseClassDecl->hasObjectMember())
setHasObjectMember(true);
// Keep track of the presence of mutable fields.
if (BaseClassDecl->hasMutableFields())
data().HasMutableFields = true;
@ -698,10 +703,23 @@ NotASpecialMember:;
// A POD struct is a class that is both a trivial class and a
// standard-layout class, and has no non-static data members of type
// non-POD struct, non-POD union (or array of such types).
//
// Automatic Reference Counting: the presence of a member of Objective-C pointer type
// that does not explicitly have no lifetime makes the class a non-POD.
// However, we delay setting PlainOldData to false in this case so that
// Sema has a chance to diagnostic causes where the same class will be
// non-POD with Automatic Reference Counting but a POD without Instant Objects.
// In this case, the class will become a non-POD class when we complete
// the definition.
ASTContext &Context = getASTContext();
QualType T = Context.getBaseElementType(Field->getType());
if (!T->isPODType())
if (T->isObjCRetainableType() || T.isObjCGCStrong()) {
if (!Context.getLangOptions().ObjCAutoRefCount ||
T.getObjCLifetime() != Qualifiers::OCL_ExplicitNone)
setHasObjectMember(true);
} else if (!T.isPODType(Context))
data().PlainOldData = false;
if (T->isReferenceType()) {
data().HasTrivialDefaultConstructor = false;
@ -768,6 +786,8 @@ NotASpecialMember:;
if (!FieldRec->hasTrivialDestructor())
data().HasTrivialDestructor = false;
if (FieldRec->hasObjectMember())
setHasObjectMember(true);
// C++0x [class]p7:
// A standard-layout class is a class that:
@ -1078,6 +1098,20 @@ void CXXRecordDecl::completeDefinition() {
void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {
RecordDecl::completeDefinition();
if (hasObjectMember() && getASTContext().getLangOptions().ObjCAutoRefCount) {
// Objective-C Automatic Reference Counting:
// If a class has a non-static data member of Objective-C pointer
// type (or array thereof), it is a non-POD type and its
// default constructor (if any), copy constructor, copy assignment
// operator, and destructor are non-trivial.
struct DefinitionData &Data = data();
Data.PlainOldData = false;
Data.HasTrivialDefaultConstructor = false;
Data.HasTrivialCopyConstructor = false;
Data.HasTrivialCopyAssignment = false;
Data.HasTrivialDestructor = false;
}
// If the class may be abstract (but hasn't been marked as such), check for
// any pure final overriders.
if (mayBeAbstract()) {

View File

@ -474,8 +474,28 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
} else // we have a factory method.
selfTy = Context.getObjCClassType();
setSelfDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(),
&Context.Idents.get("self"), selfTy));
bool selfIsConsumed = false;
if (isInstanceMethod() && Context.getLangOptions().ObjCAutoRefCount) {
selfIsConsumed = hasAttr<NSConsumesSelfAttr>();
// 'self' is always __strong, although as a special case we don't
// actually retain it except in init methods.
Qualifiers qs;
qs.setObjCLifetime(Qualifiers::OCL_Strong);
selfTy = Context.getQualifiedType(selfTy, qs);
// In addition, 'self' is const unless this is an init method.
if (getMethodFamily() != OMF_init)
selfTy = selfTy.withConst();
}
ImplicitParamDecl *self
= ImplicitParamDecl::Create(Context, this, SourceLocation(),
&Context.Idents.get("self"), selfTy);
setSelfDecl(self);
if (selfIsConsumed)
self->addAttr(new (Context) NSConsumedAttr(SourceLocation(), Context));
setCmdDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(),
&Context.Idents.get("_cmd"),

View File

@ -933,6 +933,11 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
first = false;
}
if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_strong) {
Out << (first ? ' ' : ',') << "strong";
first = false;
}
if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_copy) {
Out << (first ? ' ' : ',') << "copy";
first = false;

View File

@ -1045,6 +1045,10 @@ const char *CastExpr::getCastKindName() const {
return "IntegralComplexCast";
case CK_IntegralComplexToFloatingComplex:
return "IntegralComplexToFloatingComplex";
case CK_ObjCConsumeObject:
return "ObjCConsumeObject";
case CK_ObjCProduceObject:
return "ObjCProduceObject";
}
llvm_unreachable("Unhandled cast kind!");
@ -1490,6 +1494,17 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
case ObjCMessageExprClass: {
const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(this);
if (Ctx.getLangOptions().ObjCAutoRefCount &&
ME->isInstanceMessage() &&
!ME->getType()->isVoidType() &&
ME->getSelector().getIdentifierInfoForSlot(0) &&
ME->getSelector().getIdentifierInfoForSlot(0)
->getName().startswith("init")) {
Loc = getExprLoc();
R1 = ME->getSourceRange();
return true;
}
const ObjCMethodDecl *MD = ME->getMethodDecl();
if (MD && MD->getAttr<WarnUnusedResultAttr>()) {
Loc = getExprLoc();
@ -2519,7 +2534,7 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T,
/*TypeDependent=*/false, /*ValueDependent=*/false,
/*ContainsUnexpandedParameterPack=*/false),
NumArgs(NumArgs), Kind(IsInstanceSuper? SuperInstance : SuperClass),
HasMethod(Method != 0), SuperLoc(SuperLoc),
HasMethod(Method != 0), IsDelegateInitCall(false), SuperLoc(SuperLoc),
SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
: Sel.getAsOpaquePtr())),
SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc)
@ -2540,7 +2555,8 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T,
SourceLocation RBracLoc)
: Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, T->isDependentType(),
T->isDependentType(), T->containsUnexpandedParameterPack()),
NumArgs(NumArgs), Kind(Class), HasMethod(Method != 0),
NumArgs(NumArgs), Kind(Class),
HasMethod(Method != 0), IsDelegateInitCall(false),
SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
: Sel.getAsOpaquePtr())),
SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc)
@ -2571,7 +2587,8 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T,
: Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, Receiver->isTypeDependent(),
Receiver->isTypeDependent(),
Receiver->containsUnexpandedParameterPack()),
NumArgs(NumArgs), Kind(Instance), HasMethod(Method != 0),
NumArgs(NumArgs), Kind(Instance),
HasMethod(Method != 0), IsDelegateInitCall(false),
SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
: Sel.getAsOpaquePtr())),
SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc)
@ -2702,6 +2719,19 @@ ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const {
return 0;
}
llvm::StringRef ObjCBridgedCastExpr::getBridgeKindName() const {
switch (getBridgeKind()) {
case OBC_Bridge:
return "__bridge";
case OBC_BridgeTransfer:
return "__bridge_transfer";
case OBC_BridgeRetained:
return "__bridge_retained";
}
return "__bridge";
}
bool ChooseExpr::isConditionTrue(const ASTContext &C) const {
return getCond()->EvaluateAsInt(C) != 0;
}

View File

@ -162,6 +162,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::SizeOfPackExprClass:
case Expr::SubstNonTypeTemplateParmPackExprClass:
case Expr::AsTypeExprClass:
case Expr::ObjCIndirectCopyRestoreExprClass:
return Cl::CL_PRValue;
// Next come the complicated cases.
@ -289,6 +290,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::CXXDynamicCastExprClass:
case Expr::CXXReinterpretCastExprClass:
case Expr::CXXConstCastExprClass:
case Expr::ObjCBridgedCastExprClass:
// Only in C++ can casts be interesting at all.
if (!Lang.CPlusPlus) return Cl::CL_PRValue;
return ClassifyUnnamed(Ctx, cast<ExplicitCastExpr>(E)->getTypeAsWritten());

View File

@ -282,6 +282,17 @@ public:
return true;
return false;
}
bool VisitObjCIvarRefExpr(const ObjCIvarRefExpr *E) {
if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified())
return true;
return false;
}
bool VisitBlockDeclRefExpr (const BlockDeclRefExpr *E) {
if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified())
return true;
return false;
}
// We don't want to evaluate BlockExprs multiple times, as they generate
// a ton of code.
bool VisitBlockExpr(const BlockExpr *E) { return true; }
@ -1797,6 +1808,8 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_GetObjCProperty:
case CK_LValueBitCast:
case CK_UserDefinedConversion:
case CK_ObjCProduceObject:
case CK_ObjCConsumeObject:
return false;
case CK_LValueToRValue:
@ -2301,6 +2314,8 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_FloatingComplexToBoolean:
case CK_IntegralComplexToReal:
case CK_IntegralComplexToBoolean:
case CK_ObjCProduceObject:
case CK_ObjCConsumeObject:
llvm_unreachable("invalid cast kind for complex value");
case CK_LValueToRValue:
@ -2771,6 +2786,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::PackExpansionExprClass:
case Expr::SubstNonTypeTemplateParmPackExprClass:
case Expr::AsTypeExprClass:
case Expr::ObjCIndirectCopyRestoreExprClass:
return ICEDiag(2, E->getLocStart());
case Expr::SizeOfPackExprClass:
@ -2995,7 +3011,8 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::CXXFunctionalCastExprClass:
case Expr::CXXStaticCastExprClass:
case Expr::CXXReinterpretCastExprClass:
case Expr::CXXConstCastExprClass: {
case Expr::CXXConstCastExprClass:
case Expr::ObjCBridgedCastExprClass: {
const Expr *SubExpr = cast<CastExpr>(E)->getSubExpr();
if (SubExpr->getType()->isIntegralOrEnumerationType())
return CheckICE(SubExpr, Ctx);

View File

@ -21,6 +21,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/SourceManager.h"
@ -1464,7 +1465,35 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
Out << 'U' << ASString.size() << ASString;
}
// FIXME: For now, just drop all extension qualifiers on the floor.
llvm::StringRef LifetimeName;
switch (Quals.getObjCLifetime()) {
// Objective-C ARC Extension:
//
// <type> ::= U "__strong"
// <type> ::= U "__weak"
// <type> ::= U "__autoreleasing"
// <type> ::= U "__unsafe_unretained"
case Qualifiers::OCL_None:
break;
case Qualifiers::OCL_Weak:
LifetimeName = "__weak";
break;
case Qualifiers::OCL_Strong:
LifetimeName = "__strong";
break;
case Qualifiers::OCL_Autoreleasing:
LifetimeName = "__autoreleasing";
break;
case Qualifiers::OCL_ExplicitNone:
LifetimeName = "__unsafe_unretained";
break;
}
if (!LifetimeName.empty())
Out << 'U' << LifetimeName.size() << LifetimeName;
}
void CXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) {
@ -2089,6 +2118,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
case Expr::ObjCProtocolExprClass:
case Expr::ObjCSelectorExprClass:
case Expr::ObjCStringLiteralClass:
case Expr::ObjCIndirectCopyRestoreExprClass:
case Expr::OffsetOfExprClass:
case Expr::PredefinedExprClass:
case Expr::ShuffleVectorExprClass:
@ -2347,7 +2377,15 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
mangleExpression(cast<ImplicitCastExpr>(E)->getSubExpr(), Arity);
break;
}
case Expr::ObjCBridgedCastExprClass: {
// Mangle ownership casts as a vendor extended operator __bridge,
// __bridge_transfer, or __bridge_retain.
llvm::StringRef Kind = cast<ObjCBridgedCastExpr>(E)->getBridgeKindName();
Out << "v1U" << Kind.size() << Kind;
}
// Fall through to mangle the cast itself.
case Expr::CStyleCastExprClass:
case Expr::CXXStaticCastExprClass:
case Expr::CXXDynamicCastExprClass:

View File

@ -66,6 +66,15 @@ Stmt *ParentMap::getParentIgnoreParenCasts(Stmt *S) const {
return S;
}
Stmt *ParentMap::getOuterParenParent(Stmt *S) const {
Stmt *Paren = 0;
while (isa<ParenExpr>(S)) {
Paren = S;
S = getParent(S);
};
return Paren;
}
bool ParentMap::isConsumedExpr(Expr* E) const {
Stmt *P = getParent(E);
Stmt *DirectChild = E;

View File

@ -449,6 +449,12 @@ void StmtPrinter::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *Node) {
OS << "\n";
}
void StmtPrinter::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *Node) {
Indent() << "@autoreleasepool";
PrintRawCompoundStmt(dyn_cast<CompoundStmt>(Node->getSubStmt()));
OS << "\n";
}
void StmtPrinter::PrintRawCXXCatchStmt(CXXCatchStmt *Node) {
OS << "catch (";
if (Decl *ExDecl = Node->getExceptionDecl())
@ -1464,6 +1470,17 @@ void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) {
OS << "]";
}
void
StmtPrinter::VisitObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) {
PrintExpr(E->getSubExpr());
}
void
StmtPrinter::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
OS << "(" << E->getBridgeKindName() << E->getType().getAsString(Policy)
<< ")";
PrintExpr(E->getSubExpr());
}
void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
BlockDecl *BD = Node->getBlockDecl();

View File

@ -220,6 +220,10 @@ void StmtProfiler::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
VisitStmt(S);
}
void StmtProfiler::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
VisitStmt(S);
}
void StmtProfiler::VisitExpr(Expr *S) {
VisitStmt(S);
}
@ -952,6 +956,17 @@ void StmtProfiler::VisitObjCIsaExpr(ObjCIsaExpr *S) {
ID.AddBoolean(S->isArrow());
}
void
StmtProfiler::VisitObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *S) {
VisitExpr(S);
ID.AddBoolean(S->shouldCopy());
}
void StmtProfiler::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *S) {
VisitExplicitCastExpr(S);
ID.AddBoolean(S->getBridgeKind());
}
void StmtProfiler::VisitDecl(Decl *D) {
ID.AddInteger(D? D->getKind() : 0);

View File

@ -36,7 +36,10 @@ bool Qualifiers::isStrictSupersetOf(Qualifiers Other) const {
(hasObjCGCAttr() && !Other.hasObjCGCAttr())) &&
// Address space superset.
((getAddressSpace() == Other.getAddressSpace()) ||
(hasAddressSpace()&& !Other.hasAddressSpace()));
(hasAddressSpace()&& !Other.hasAddressSpace())) &&
// Lifetime qualifier superset.
((getObjCLifetime() == Other.getObjCLifetime()) ||
(hasObjCLifetime() && !Other.hasObjCLifetime()));
}
bool QualType::isConstant(QualType T, ASTContext &Ctx) {
@ -866,39 +869,59 @@ bool Type::isIncompleteType() const {
}
}
/// isPODType - Return true if this is a plain-old-data type (C++ 3.9p10)
bool Type::isPODType() const {
bool QualType::isPODType(ASTContext &Context) const {
// The compiler shouldn't query this for incomplete types, but the user might.
// We return false for that case. Except for incomplete arrays of PODs, which
// are PODs according to the standard.
if (isIncompleteArrayType() &&
cast<ArrayType>(CanonicalType)->getElementType()->isPODType())
return true;
if (isIncompleteType())
if (isNull())
return 0;
if ((*this)->isIncompleteArrayType())
return Context.getBaseElementType(*this).isPODType(Context);
if ((*this)->isIncompleteType())
return false;
if (Context.getLangOptions().ObjCAutoRefCount) {
switch (getObjCLifetime()) {
case Qualifiers::OCL_ExplicitNone:
return true;
case Qualifiers::OCL_Strong:
case Qualifiers::OCL_Weak:
case Qualifiers::OCL_Autoreleasing:
return false;
case Qualifiers::OCL_None:
if ((*this)->isObjCLifetimeType())
return false;
break;
}
}
QualType CanonicalType = getTypePtr()->CanonicalType;
switch (CanonicalType->getTypeClass()) {
// Everything not explicitly mentioned is not POD.
default: return false;
case VariableArray:
case ConstantArray:
case Type::VariableArray:
case Type::ConstantArray:
// IncompleteArray is handled above.
return cast<ArrayType>(CanonicalType)->getElementType()->isPODType();
case Builtin:
case Complex:
case Pointer:
case MemberPointer:
case Vector:
case ExtVector:
case ObjCObjectPointer:
case BlockPointer:
return Context.getBaseElementType(*this).isPODType(Context);
case Type::ObjCObjectPointer:
case Type::BlockPointer:
case Type::Builtin:
case Type::Complex:
case Type::Pointer:
case Type::MemberPointer:
case Type::Vector:
case Type::ExtVector:
return true;
case Enum:
case Type::Enum:
return true;
case Record:
case Type::Record:
if (CXXRecordDecl *ClassDecl
= dyn_cast<CXXRecordDecl>(cast<RecordType>(CanonicalType)->getDecl()))
return ClassDecl->isPOD();
@ -908,6 +931,121 @@ bool Type::isPODType() const {
}
}
bool QualType::isTrivialType(ASTContext &Context) const {
// The compiler shouldn't query this for incomplete types, but the user might.
// We return false for that case. Except for incomplete arrays of PODs, which
// are PODs according to the standard.
if (isNull())
return 0;
if ((*this)->isArrayType())
return Context.getBaseElementType(*this).isTrivialType(Context);
// Return false for incomplete types after skipping any incomplete array
// types which are expressly allowed by the standard and thus our API.
if ((*this)->isIncompleteType())
return false;
if (Context.getLangOptions().ObjCAutoRefCount) {
switch (getObjCLifetime()) {
case Qualifiers::OCL_ExplicitNone:
return true;
case Qualifiers::OCL_Strong:
case Qualifiers::OCL_Weak:
case Qualifiers::OCL_Autoreleasing:
return false;
case Qualifiers::OCL_None:
if ((*this)->isObjCLifetimeType())
return false;
break;
}
}
QualType CanonicalType = getTypePtr()->CanonicalType;
if (CanonicalType->isDependentType())
return false;
// C++0x [basic.types]p9:
// Scalar types, trivial class types, arrays of such types, and
// cv-qualified versions of these types are collectively called trivial
// types.
// As an extension, Clang treats vector types as Scalar types.
if (CanonicalType->isScalarType() || CanonicalType->isVectorType())
return true;
if (const RecordType *RT = CanonicalType->getAs<RecordType>()) {
if (const CXXRecordDecl *ClassDecl =
dyn_cast<CXXRecordDecl>(RT->getDecl())) {
// C++0x [class]p5:
// A trivial class is a class that has a trivial default constructor
if (!ClassDecl->hasTrivialDefaultConstructor()) return false;
// and is trivially copyable.
if (!ClassDecl->isTriviallyCopyable()) return false;
}
return true;
}
// No other types can match.
return false;
}
bool QualType::isTriviallyCopyableType(ASTContext &Context) const {
if ((*this)->isArrayType())
return Context.getBaseElementType(*this).isTrivialType(Context);
if (Context.getLangOptions().ObjCAutoRefCount) {
switch (getObjCLifetime()) {
case Qualifiers::OCL_ExplicitNone:
return true;
case Qualifiers::OCL_Strong:
case Qualifiers::OCL_Weak:
case Qualifiers::OCL_Autoreleasing:
return false;
case Qualifiers::OCL_None:
if ((*this)->isObjCLifetimeType())
return false;
break;
}
}
// C++0x [basic.types]p9
// Scalar types, trivially copyable class types, arrays of such types, and
// cv-qualified versions of these types are collectively called trivial
// types.
QualType CanonicalType = getCanonicalType();
if (CanonicalType->isDependentType())
return false;
// Return false for incomplete types after skipping any incomplete array types
// which are expressly allowed by the standard and thus our API.
if (CanonicalType->isIncompleteType())
return false;
// As an extension, Clang treats vector types as Scalar types.
if (CanonicalType->isScalarType() || CanonicalType->isVectorType())
return true;
if (const RecordType *RT = CanonicalType->getAs<RecordType>()) {
if (const CXXRecordDecl *ClassDecl =
dyn_cast<CXXRecordDecl>(RT->getDecl())) {
if (!ClassDecl->isTriviallyCopyable()) return false;
}
return true;
}
// No other types can match.
return false;
}
bool Type::isLiteralType() const {
if (isDependentType())
return false;
@ -928,6 +1066,10 @@ bool Type::isLiteralType() const {
if (BaseTy->isIncompleteType())
return false;
// Objective-C lifetime types are not literal types.
if (BaseTy->isObjCRetainableType())
return false;
// C++0x [basic.types]p10:
// A type is a literal type if it is:
// -- a scalar type; or
@ -961,68 +1103,6 @@ bool Type::isLiteralType() const {
return false;
}
bool Type::isTrivialType() const {
if (isDependentType())
return false;
// C++0x [basic.types]p9:
// Scalar types, trivial class types, arrays of such types, and
// cv-qualified versions of these types are collectively called trivial
// types.
const Type *BaseTy = getBaseElementTypeUnsafe();
assert(BaseTy && "NULL element type");
// Return false for incomplete types after skipping any incomplete array
// types which are expressly allowed by the standard and thus our API.
if (BaseTy->isIncompleteType())
return false;
// As an extension, Clang treats vector types as Scalar types.
if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true;
if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
if (const CXXRecordDecl *ClassDecl =
dyn_cast<CXXRecordDecl>(RT->getDecl())) {
if (!ClassDecl->isTrivial()) return false;
}
return true;
}
// No other types can match.
return false;
}
bool Type::isTriviallyCopyableType() const {
if (isDependentType())
return false;
// C++0x [basic.types]p9
// Scalar types, trivially copyable class types, arrays of such types, and
// cv-qualified versions of these types are collectively called trivial
// types.
const Type *BaseTy = getBaseElementTypeUnsafe();
assert(BaseTy && "NULL element type");
// Return false for incomplete types after skipping any incomplete array types
// which are expressly allowed by the standard and thus our API.
if (BaseTy->isIncompleteType())
return false;
// As an extension, Clang treats vector types as Scalar types.
if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true;
if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
if (const CXXRecordDecl *ClassDecl =
dyn_cast<CXXRecordDecl>(RT->getDecl())) {
if (!ClassDecl->isTriviallyCopyable()) return false;
}
return true;
}
// No other types can match.
return false;
}
bool Type::isStandardLayoutType() const {
if (isDependentType())
return false;
@ -1060,14 +1140,32 @@ bool Type::isStandardLayoutType() const {
// This is effectively the intersection of isTrivialType and
// isStandardLayoutType. We implement it dircetly to avoid redundant
// conversions from a type to a CXXRecordDecl.
bool Type::isCXX11PODType() const {
if (isDependentType())
bool QualType::isCXX11PODType(ASTContext &Context) const {
const Type *ty = getTypePtr();
if (ty->isDependentType())
return false;
if (Context.getLangOptions().ObjCAutoRefCount) {
switch (getObjCLifetime()) {
case Qualifiers::OCL_ExplicitNone:
return true;
case Qualifiers::OCL_Strong:
case Qualifiers::OCL_Weak:
case Qualifiers::OCL_Autoreleasing:
return false;
case Qualifiers::OCL_None:
if (ty->isObjCLifetimeType())
return false;
break;
}
}
// C++11 [basic.types]p9:
// Scalar types, POD classes, arrays of such types, and cv-qualified
// versions of these types are collectively called trivial types.
const Type *BaseTy = getBaseElementTypeUnsafe();
const Type *BaseTy = ty->getBaseElementTypeUnsafe();
assert(BaseTy && "NULL element type");
// Return false for incomplete types after skipping any incomplete array
@ -1392,7 +1490,8 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
result->containsUnexpandedParameterPack(),
epi.ExtInfo),
NumArgs(numArgs), NumExceptions(epi.NumExceptions),
ExceptionSpecType(epi.ExceptionSpecType)
ExceptionSpecType(epi.ExceptionSpecType),
HasAnyConsumedArgs(epi.ConsumedArguments != 0)
{
// Fill in the trailing argument array.
QualType *argSlot = reinterpret_cast<QualType*>(this+1);
@ -1423,6 +1522,12 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
Expr **noexSlot = reinterpret_cast<Expr**>(argSlot + numArgs);
*noexSlot = epi.NoexceptExpr;
}
if (epi.ConsumedArguments) {
bool *consumedArgs = const_cast<bool*>(getConsumedArgsBuffer());
for (unsigned i = 0; i != numArgs; ++i)
consumedArgs[i] = epi.ConsumedArguments[i];
}
}
FunctionProtoType::NoexceptResult
@ -1461,6 +1566,24 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
const QualType *ArgTys, unsigned NumArgs,
const ExtProtoInfo &epi,
const ASTContext &Context) {
// We have to be careful not to get ambiguous profile encodings.
// Note that valid type pointers are never ambiguous with anything else.
//
// The encoding grammar begins:
// type type* bool int bool
// If that final bool is true, then there is a section for the EH spec:
// bool type*
// This is followed by an optional "consumed argument" section of the
// same length as the first type sequence:
// bool*
// Finally, we have the ext info:
// int
//
// There is no ambiguity between the consumed arguments and an empty EH
// spec because of the leading 'bool' which unambiguously indicates
// whether the following bool is the EH spec or part of the arguments.
ID.AddPointer(Result.getAsOpaquePtr());
for (unsigned i = 0; i != NumArgs; ++i)
ID.AddPointer(ArgTys[i].getAsOpaquePtr());
@ -1474,6 +1597,10 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
} else if (epi.ExceptionSpecType == EST_ComputedNoexcept && epi.NoexceptExpr){
epi.NoexceptExpr->Profile(ID, Context, false);
}
if (epi.ConsumedArguments) {
for (unsigned i = 0; i != NumArgs; ++i)
ID.AddBoolean(epi.ConsumedArguments[i]);
}
epi.ExtInfo.Profile(ID);
}
@ -1900,6 +2027,79 @@ void Type::ClearLinkageCache() {
CanonicalType->TypeBits.CacheValidAndVisibility = 0;
}
Qualifiers::ObjCLifetime Type::getObjCARCImplicitLifetime() const {
if (isObjCARCImplicitlyUnretainedType())
return Qualifiers::OCL_ExplicitNone;
return Qualifiers::OCL_Strong;
}
bool Type::isObjCARCImplicitlyUnretainedType() const {
assert(isObjCLifetimeType() &&
"cannot query implicit lifetime for non-inferrable type");
const Type *canon = getCanonicalTypeInternal().getTypePtr();
// Walk down to the base type. We don't care about qualifiers for this.
while (const ArrayType *array = dyn_cast<ArrayType>(canon))
canon = array->getElementType().getTypePtr();
if (const ObjCObjectPointerType *opt
= dyn_cast<ObjCObjectPointerType>(canon)) {
// Class and Class<Protocol> don't require retension.
if (opt->getObjectType()->isObjCClass())
return true;
}
return false;
}
bool Type::isObjCNSObjectType() const {
if (const TypedefType *typedefType = dyn_cast<TypedefType>(this))
return typedefType->getDecl()->hasAttr<ObjCNSObjectAttr>();
return false;
}
bool Type::isObjCRetainableType() const {
return isObjCObjectPointerType() ||
isBlockPointerType() ||
isObjCNSObjectType();
}
bool Type::isObjCIndirectLifetimeType() const {
if (isObjCLifetimeType())
return true;
if (const PointerType *OPT = getAs<PointerType>())
return OPT->getPointeeType()->isObjCIndirectLifetimeType();
if (const ReferenceType *Ref = getAs<ReferenceType>())
return Ref->getPointeeType()->isObjCIndirectLifetimeType();
if (const MemberPointerType *MemPtr = getAs<MemberPointerType>())
return MemPtr->getPointeeType()->isObjCIndirectLifetimeType();
return false;
}
/// Returns true if objects of this type have lifetime semantics under
/// ARC.
bool Type::isObjCLifetimeType() const {
const Type *type = this;
while (const ArrayType *array = type->getAsArrayTypeUnsafe())
type = array->getElementType().getTypePtr();
return type->isObjCRetainableType();
}
/// \brief Determine whether the given type T is a "bridgable" Objective-C type,
/// which is either an Objective-C object pointer type or an
bool Type::isObjCARCBridgableType() const {
return isObjCObjectPointerType() || isBlockPointerType();
}
/// \brief Determine whether the given type T is a "bridgeable" C type.
bool Type::isCARCBridgableType() const {
const PointerType *Pointer = getAs<PointerType>();
if (!Pointer)
return false;
QualType Pointee = Pointer->getPointeeType();
return Pointee->isVoidType() || Pointee->isRecordType();
}
bool Type::hasSizedVLAType() const {
if (!isVariablyModifiedType()) return false;
@ -1919,6 +2119,18 @@ bool Type::hasSizedVLAType() const {
}
QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) {
switch (type.getObjCLifetime()) {
case Qualifiers::OCL_None:
case Qualifiers::OCL_ExplicitNone:
case Qualifiers::OCL_Autoreleasing:
break;
case Qualifiers::OCL_Strong:
return DK_objc_strong_lifetime;
case Qualifiers::OCL_Weak:
return DK_objc_weak_lifetime;
}
/// Currently, the only destruction kind we recognize is C++ objects
/// with non-trivial destructors.
const CXXRecordDecl *record =
@ -1928,3 +2140,24 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) {
return DK_none;
}
bool QualType::hasTrivialCopyAssignment(ASTContext &Context) const {
switch (getObjCLifetime()) {
case Qualifiers::OCL_None:
break;
case Qualifiers::OCL_ExplicitNone:
return true;
case Qualifiers::OCL_Autoreleasing:
case Qualifiers::OCL_Strong:
case Qualifiers::OCL_Weak:
return !Context.getLangOptions().ObjCAutoRefCount;
}
if (const CXXRecordDecl *Record
= getTypePtr()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl())
return Record->hasTrivialCopyAssignment();
return true;
}

View File

@ -24,6 +24,23 @@
using namespace clang;
namespace {
/// \brief RAII object that enables printing of the ARC __strong lifetime
/// qualifier.
class IncludeStrongLifetimeRAII {
PrintingPolicy &Policy;
bool Old;
public:
explicit IncludeStrongLifetimeRAII(PrintingPolicy &Policy)
: Policy(Policy), Old(Policy.SuppressStrongLifetime) {
Policy.SuppressStrongLifetime = false;
}
~IncludeStrongLifetimeRAII() {
Policy.SuppressStrongLifetime = Old;
}
};
class TypePrinter {
PrintingPolicy Policy;
@ -78,7 +95,7 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
// "int * const", printing "const int *" is different. Only do this when the
// type expands to a simple string.
bool CanPrefixQualifiers = false;
bool NeedARCStrongQualifier = false;
Type::TypeClass TC = T->getTypeClass();
if (const AutoType *AT = dyn_cast<AutoType>(T))
TC = AT->desugar()->getTypeClass();
@ -114,15 +131,18 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
T->isObjCQualifiedIdType() || T->isObjCQualifiedClassType();
break;
case Type::ConstantArray:
case Type::IncompleteArray:
case Type::VariableArray:
case Type::DependentSizedArray:
NeedARCStrongQualifier = true;
// Fall through
case Type::Pointer:
case Type::BlockPointer:
case Type::LValueReference:
case Type::RValueReference:
case Type::MemberPointer:
case Type::ConstantArray:
case Type::IncompleteArray:
case Type::VariableArray:
case Type::DependentSizedArray:
case Type::DependentSizedExtVector:
case Type::Vector:
case Type::ExtVector:
@ -139,13 +159,20 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
if (!CanPrefixQualifiers && !Quals.empty()) {
std::string qualsBuffer;
Quals.getAsStringInternal(qualsBuffer, Policy);
if (!buffer.empty()) {
qualsBuffer += ' ';
qualsBuffer += buffer;
if (NeedARCStrongQualifier) {
IncludeStrongLifetimeRAII Strong(Policy);
Quals.getAsStringInternal(qualsBuffer, Policy);
} else {
Quals.getAsStringInternal(qualsBuffer, Policy);
}
if (!qualsBuffer.empty()) {
if (!buffer.empty()) {
qualsBuffer += ' ';
qualsBuffer += buffer;
}
std::swap(buffer, qualsBuffer);
}
std::swap(buffer, qualsBuffer);
}
switch (T->getTypeClass()) {
@ -159,13 +186,20 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
// If we're adding the qualifiers as a prefix, do it now.
if (CanPrefixQualifiers && !Quals.empty()) {
std::string qualsBuffer;
Quals.getAsStringInternal(qualsBuffer, Policy);
if (!buffer.empty()) {
qualsBuffer += ' ';
qualsBuffer += buffer;
if (NeedARCStrongQualifier) {
IncludeStrongLifetimeRAII Strong(Policy);
Quals.getAsStringInternal(qualsBuffer, Policy);
} else {
Quals.getAsStringInternal(qualsBuffer, Policy);
}
if (!qualsBuffer.empty()) {
if (!buffer.empty()) {
qualsBuffer += ' ';
qualsBuffer += buffer;
}
std::swap(buffer, qualsBuffer);
}
std::swap(buffer, qualsBuffer);
}
}
@ -192,6 +226,7 @@ void TypePrinter::printPointer(const PointerType *T, std::string &S) {
if (isa<ArrayType>(T->getPointeeType()))
S = '(' + S + ')';
IncludeStrongLifetimeRAII Strong(Policy);
print(T->getPointeeType(), S);
}
@ -209,6 +244,7 @@ void TypePrinter::printLValueReference(const LValueReferenceType *T,
if (isa<ArrayType>(T->getPointeeTypeAsWritten()))
S = '(' + S + ')';
IncludeStrongLifetimeRAII Strong(Policy);
print(T->getPointeeTypeAsWritten(), S);
}
@ -221,6 +257,7 @@ void TypePrinter::printRValueReference(const RValueReferenceType *T,
if (isa<ArrayType>(T->getPointeeTypeAsWritten()))
S = '(' + S + ')';
IncludeStrongLifetimeRAII Strong(Policy);
print(T->getPointeeTypeAsWritten(), S);
}
@ -236,6 +273,7 @@ void TypePrinter::printMemberPointer(const MemberPointerType *T,
if (isa<ArrayType>(T->getPointeeType()))
S = '(' + S + ')';
IncludeStrongLifetimeRAII Strong(Policy);
print(T->getPointeeType(), S);
}
@ -245,12 +283,14 @@ void TypePrinter::printConstantArray(const ConstantArrayType *T,
S += llvm::utostr(T->getSize().getZExtValue());
S += ']';
IncludeStrongLifetimeRAII Strong(Policy);
print(T->getElementType(), S);
}
void TypePrinter::printIncompleteArray(const IncompleteArrayType *T,
std::string &S) {
S += "[]";
IncludeStrongLifetimeRAII Strong(Policy);
print(T->getElementType(), S);
}
@ -276,6 +316,7 @@ void TypePrinter::printVariableArray(const VariableArrayType *T,
}
S += ']';
IncludeStrongLifetimeRAII Strong(Policy);
print(T->getElementType(), S);
}
@ -291,6 +332,7 @@ void TypePrinter::printDependentSizedArray(const DependentSizedArrayType *T,
}
S += ']';
IncludeStrongLifetimeRAII Strong(Policy);
print(T->getElementType(), S);
}
@ -518,6 +560,7 @@ void TypePrinter::printUnaryTransform(const UnaryTransformType *T,
if (!S.empty())
S = ' ' + S;
std::string Str;
IncludeStrongLifetimeRAII Strong(Policy);
print(T->getBaseType(), Str);
switch (T->getUTTKind()) {
@ -552,6 +595,7 @@ void TypePrinter::AppendScope(DeclContext *DC, std::string &Buffer) {
Buffer += "<anonymous>";
} else if (ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(DC)) {
IncludeStrongLifetimeRAII Strong(Policy);
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
std::string TemplateArgsStr
= TemplateSpecializationType::PrintTemplateArgumentList(
@ -642,6 +686,7 @@ void TypePrinter::printTag(TagDecl *D, std::string &InnerString) {
Args = TemplateArgs.data();
NumArgs = TemplateArgs.size();
}
IncludeStrongLifetimeRAII Strong(Policy);
Buffer += TemplateSpecializationType::PrintTemplateArgumentList(Args,
NumArgs,
Policy);
@ -677,18 +722,21 @@ void TypePrinter::printTemplateTypeParm(const TemplateTypeParmType *T,
void TypePrinter::printSubstTemplateTypeParm(const SubstTemplateTypeParmType *T,
std::string &S) {
IncludeStrongLifetimeRAII Strong(Policy);
print(T->getReplacementType(), S);
}
void TypePrinter::printSubstTemplateTypeParmPack(
const SubstTemplateTypeParmPackType *T,
std::string &S) {
IncludeStrongLifetimeRAII Strong(Policy);
printTemplateTypeParm(T->getReplacedParameter(), S);
}
void TypePrinter::printTemplateSpecialization(
const TemplateSpecializationType *T,
std::string &S) {
IncludeStrongLifetimeRAII Strong(Policy);
std::string SpecString;
{
@ -765,6 +813,7 @@ void TypePrinter::printDependentName(const DependentNameType *T, std::string &S)
void TypePrinter::printDependentTemplateSpecialization(
const DependentTemplateSpecializationType *T, std::string &S) {
IncludeStrongLifetimeRAII Strong(Policy);
std::string MyString;
{
llvm::raw_string_ostream OS(MyString);
@ -796,8 +845,9 @@ void TypePrinter::printPackExpansion(const PackExpansionType *T,
void TypePrinter::printAttributed(const AttributedType *T,
std::string &S) {
// Prefer the macro forms of the GC qualifiers.
if (T->getAttrKind() == AttributedType::attr_objc_gc)
// Prefer the macro forms of the GC and lifetime qualifiers.
if (T->getAttrKind() == AttributedType::attr_objc_gc ||
T->getAttrKind() == AttributedType::attr_objc_lifetime)
return print(T->getEquivalentType(), S);
print(T->getModifiedType(), S);
@ -866,6 +916,18 @@ void TypePrinter::printAttributed(const AttributedType *T,
break;
}
case AttributedType::attr_objc_lifetime:
S += "objc_lifetime(";
switch (T->getEquivalentType().getObjCLifetime()) {
case Qualifiers::OCL_None: llvm_unreachable("no lifetime!"); break;
case Qualifiers::OCL_ExplicitNone: S += "none"; break;
case Qualifiers::OCL_Strong: S += "strong"; break;
case Qualifiers::OCL_Weak: S += "weak"; break;
case Qualifiers::OCL_Autoreleasing: S += "autoreleasing"; break;
}
S += ")";
break;
case AttributedType::attr_noreturn: S += "noreturn"; break;
case AttributedType::attr_cdecl: S += "cdecl"; break;
case AttributedType::attr_fastcall: S += "fastcall"; break;
@ -1080,7 +1142,7 @@ std::string Qualifiers::getAsString() const {
// prefix a space if the string is non-empty. Will not append a final
// space.
void Qualifiers::getAsStringInternal(std::string &S,
const PrintingPolicy&) const {
const PrintingPolicy& Policy) const {
AppendTypeQualList(S, getCVRQualifiers());
if (unsigned addrspace = getAddressSpace()) {
if (!S.empty()) S += ' ';
@ -1095,6 +1157,23 @@ void Qualifiers::getAsStringInternal(std::string &S,
else
S += "__strong";
}
if (Qualifiers::ObjCLifetime lifetime = getObjCLifetime()) {
if (!S.empty() &&
!(lifetime == Qualifiers::OCL_Strong && Policy.SuppressStrongLifetime))
S += ' ';
switch (lifetime) {
case Qualifiers::OCL_None: llvm_unreachable("none but true");
case Qualifiers::OCL_ExplicitNone: S += "__unsafe_unretained"; break;
case Qualifiers::OCL_Strong:
if (!Policy.SuppressStrongLifetime)
S += "__strong";
break;
case Qualifiers::OCL_Weak: S += "__weak"; break;
case Qualifiers::OCL_Autoreleasing: S += "__autoreleasing"; break;
}
}
}
std::string QualType::getAsString(const Type *ty, Qualifiers qs) {

View File

@ -16,6 +16,7 @@
#include "llvm/ADT/SmallVector.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Analysis/Analyses/ReachableCode.h"
#include "clang/Analysis/CFG.h"
@ -108,6 +109,11 @@ static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1,
case Stmt::CXXTryStmtClass: {
return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc();
}
case Expr::ObjCBridgedCastExprClass: {
const ObjCBridgedCastExpr *CSC = cast<ObjCBridgedCastExpr>(S);
R1 = CSC->getSubExpr()->getSourceRange();
return CSC->getLParenLoc();
}
default: ;
}
R1 = S->getSourceRange();

View File

@ -740,5 +740,10 @@ bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const {
DiagID == diag::err_unavailable_message)
return false;
// Currently we consider all ARC errors as recoverable.
if (getCategoryNumberForDiag(DiagID) ==
diag::DiagCat_Automatic_Reference_Counting_Issue)
return false;
return true;
}

View File

@ -17,6 +17,7 @@
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdio>
@ -92,7 +93,8 @@ namespace {
KEYBORLAND = 0x100,
KEYOPENCL = 0x200,
KEYC1X = 0x400,
KEYALL = 0x7ff
KEYARC = 0x800,
KEYALL = 0x0fff
};
}
@ -120,7 +122,8 @@ static void AddKeyword(llvm::StringRef Keyword,
else if (LangOpts.OpenCL && (Flags & KEYOPENCL)) AddResult = 2;
else if (!LangOpts.CPlusPlus && (Flags & KEYNOCXX)) AddResult = 2;
else if (LangOpts.C1X && (Flags & KEYC1X)) AddResult = 2;
else if (LangOpts.ObjCAutoRefCount && (Flags & KEYARC)) AddResult = 2;
// Don't add this keyword if disabled in this language.
if (AddResult == 0) return;

View File

@ -84,15 +84,35 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
Builder.defineMacro("__MACH__");
Builder.defineMacro("OBJC_NEW_PROPERTIES");
// __weak is always defined, for use in blocks and with objc pointers.
Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))");
// Darwin defines __strong even in C mode (just to nothing).
if (!Opts.ObjC1 || Opts.getGCMode() == LangOptions::NonGC)
Builder.defineMacro("__strong", "");
else
Builder.defineMacro("__strong", "__attribute__((objc_gc(strong)))");
if (Opts.ObjCAutoRefCount) {
Builder.defineMacro("__weak", "__attribute__((objc_lifetime(weak)))");
Builder.defineMacro("__strong", "__attribute__((objc_lifetime(strong)))");
Builder.defineMacro("__autoreleasing",
"__attribute__((objc_lifetime(autoreleasing)))");
Builder.defineMacro("__unsafe_unretained",
"__attribute__((objc_lifetime(none)))");
} else {
// __weak is always defined, for use in blocks and with objc pointers.
Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))");
// Darwin defines __strong even in C mode (just to nothing).
if (Opts.getGCMode() != LangOptions::NonGC)
Builder.defineMacro("__strong", "__attribute__((objc_gc(strong)))");
else
Builder.defineMacro("__strong", "");
// __unsafe_unretained is defined to nothing in non-ARC mode. We even
// allow this in C, since one might have block pointers in structs that
// are used in pure C code and in Objective-C ARC.
Builder.defineMacro("__unsafe_unretained", "");
// The Objective-C bridged cast keywords are defined to nothing in non-ARC
// mode; then they become normal, C-style casts.
Builder.defineMacro("__bridge", "");
Builder.defineMacro("__bridge_transfer", "");
Builder.defineMacro("__bridge_retained", "");
}
if (Opts.Static)
Builder.defineMacro("__STATIC__");
else

View File

@ -347,13 +347,23 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) {
continue;
}
// Block pointers require copy/dispose.
if (variable->getType()->isBlockPointerType()) {
info.NeedsCopyDispose = true;
// If we have a lifetime qualifier, honor it for capture purposes.
// That includes *not* copying it if it's __unsafe_unretained.
if (Qualifiers::ObjCLifetime lifetime
= variable->getType().getObjCLifetime()) {
switch (lifetime) {
case Qualifiers::OCL_None: llvm_unreachable("impossible");
case Qualifiers::OCL_ExplicitNone:
case Qualifiers::OCL_Autoreleasing:
break;
// So do Objective-C pointers.
} else if (variable->getType()->isObjCObjectPointerType() ||
C.isObjCNSObjectType(variable->getType())) {
case Qualifiers::OCL_Strong:
case Qualifiers::OCL_Weak:
info.NeedsCopyDispose = true;
}
// Block pointers require copy/dispose. So do Objective-C pointers.
} else if (variable->getType()->isObjCRetainableType()) {
info.NeedsCopyDispose = true;
// So do types that require non-trivial copy construction.
@ -591,6 +601,11 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
// Otherwise, fake up a POD copy into the block field.
} else {
// Fake up a new variable so that EmitScalarInit doesn't think
// we're referring to the variable in its own initializer.
ImplicitParamDecl blockFieldPseudoVar(/*DC*/ 0, SourceLocation(),
/*name*/ 0, type);
// We use one of these or the other depending on whether the
// reference is nested.
DeclRefExpr notNested(const_cast<VarDecl*>(variable), type, VK_LValue,
@ -603,15 +618,29 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
ImplicitCastExpr l2r(ImplicitCastExpr::OnStack, type, CK_LValueToRValue,
declRef, VK_RValue);
EmitExprAsInit(&l2r, variable, blockField,
EmitExprAsInit(&l2r, &blockFieldPseudoVar, blockField,
getContext().getDeclAlign(variable),
/*captured by init*/ false);
}
// Push a destructor if necessary. The semantics for when this
// actually gets run are really obscure.
if (!ci->isByRef() && CGM.getLangOptions().CPlusPlus)
PushDestructorCleanup(type, blockField);
if (!ci->isByRef()) {
switch (type.isDestructedType()) {
case QualType::DK_none:
break;
case QualType::DK_cxx_destructor:
PushDestructorCleanup(type, blockField);
break;
case QualType::DK_objc_strong_lifetime:
PushARCReleaseCleanup(getARCCleanupKind(), type, blockField, false);
break;
case QualType::DK_objc_weak_lifetime:
// __weak objects on the stack always get EH cleanups.
PushARCWeakReleaseCleanup(NormalAndEHCleanup, type, blockField);
break;
}
}
}
// Cast to the converted block-pointer type, which happens (somewhat
@ -1023,8 +1052,6 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
llvm::Constant *
CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
ASTContext &C = getContext();
@ -1084,21 +1111,40 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
if (capture.isConstant()) continue;
const Expr *copyExpr = ci->getCopyExpr();
unsigned flags = 0;
BlockFieldFlags flags;
bool isARCWeakCapture = false;
if (copyExpr) {
assert(!ci->isByRef());
// don't bother computing flags
} else if (ci->isByRef()) {
flags = BLOCK_FIELD_IS_BYREF;
if (type.isObjCGCWeak()) flags |= BLOCK_FIELD_IS_WEAK;
} else if (type->isBlockPointerType()) {
flags = BLOCK_FIELD_IS_BLOCK;
} else if (type->isObjCObjectPointerType() || C.isObjCNSObjectType(type)) {
flags = BLOCK_FIELD_IS_OBJECT;
}
if (type.isObjCGCWeak())
flags |= BLOCK_FIELD_IS_WEAK;
if (!copyExpr && !flags) continue;
} else if (type->isObjCRetainableType()) {
flags = BLOCK_FIELD_IS_OBJECT;
if (type->isBlockPointerType())
flags = BLOCK_FIELD_IS_BLOCK;
// Special rules for ARC captures:
if (getLangOptions().ObjCAutoRefCount) {
Qualifiers qs = type.getQualifiers();
// Don't generate special copy logic for a captured object
// unless it's __strong or __weak.
if (!qs.hasStrongOrWeakObjCLifetime())
continue;
// Support __weak direct captures.
if (qs.getObjCLifetime() == Qualifiers::OCL_Weak)
isARCWeakCapture = true;
}
} else {
continue;
}
unsigned index = capture.getIndex();
llvm::Value *srcField = Builder.CreateStructGEP(src, index);
@ -1107,12 +1153,14 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
// If there's an explicit copy expression, we do that.
if (copyExpr) {
EmitSynthesizedCXXCopyCtor(dstField, srcField, copyExpr);
} else if (isARCWeakCapture) {
EmitARCCopyWeak(dstField, srcField);
} else {
llvm::Value *srcValue = Builder.CreateLoad(srcField, "blockcopy.src");
srcValue = Builder.CreateBitCast(srcValue, VoidPtrTy);
llvm::Value *dstAddr = Builder.CreateBitCast(dstField, VoidPtrTy);
Builder.CreateCall3(CGM.getBlockObjectAssign(), dstAddr, srcValue,
llvm::ConstantInt::get(Int32Ty, flags));
llvm::ConstantInt::get(Int32Ty, flags.getBitMask()));
}
}
@ -1176,20 +1224,37 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
BlockFieldFlags flags;
const CXXDestructorDecl *dtor = 0;
bool isARCWeakCapture = false;
if (ci->isByRef()) {
flags = BLOCK_FIELD_IS_BYREF;
if (type.isObjCGCWeak()) flags |= BLOCK_FIELD_IS_WEAK;
} else if (type->isBlockPointerType()) {
flags = BLOCK_FIELD_IS_BLOCK;
} else if (type->isObjCObjectPointerType() || C.isObjCNSObjectType(type)) {
if (type.isObjCGCWeak())
flags |= BLOCK_FIELD_IS_WEAK;
} else if (const CXXRecordDecl *record = type->getAsCXXRecordDecl()) {
if (record->hasTrivialDestructor())
continue;
dtor = record->getDestructor();
} else if (type->isObjCRetainableType()) {
flags = BLOCK_FIELD_IS_OBJECT;
} else if (C.getLangOptions().CPlusPlus) {
if (const CXXRecordDecl *record = type->getAsCXXRecordDecl())
if (!record->hasTrivialDestructor())
dtor = record->getDestructor();
}
if (type->isBlockPointerType())
flags = BLOCK_FIELD_IS_BLOCK;
if (!dtor && flags.empty()) continue;
// Special rules for ARC captures.
if (getLangOptions().ObjCAutoRefCount) {
Qualifiers qs = type.getQualifiers();
// Don't generate special dispose logic for a captured object
// unless it's __strong or __weak.
if (!qs.hasStrongOrWeakObjCLifetime())
continue;
// Support __weak direct captures.
if (qs.getObjCLifetime() == Qualifiers::OCL_Weak)
isARCWeakCapture = true;
}
} else {
continue;
}
unsigned index = capture.getIndex();
llvm::Value *srcField = Builder.CreateStructGEP(src, index);
@ -1198,6 +1263,10 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
if (dtor) {
PushDestructorCleanup(dtor, srcField);
// If this is a __weak capture, emit the release directly.
} else if (isARCWeakCapture) {
EmitARCDestroyWeak(srcField);
// Otherwise we call _Block_object_dispose. It wouldn't be too
// hard to just emit this as a cleanup if we wanted to make sure
// that things were done in reverse.
@ -1251,6 +1320,55 @@ public:
}
};
/// Emits the copy/dispose helpers for an ARC __block __weak variable.
class ARCWeakByrefHelpers : public CodeGenModule::ByrefHelpers {
public:
ARCWeakByrefHelpers(CharUnits alignment) : ByrefHelpers(alignment) {}
void emitCopy(CodeGenFunction &CGF, llvm::Value *destField,
llvm::Value *srcField) {
CGF.EmitARCMoveWeak(destField, srcField);
}
void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
CGF.EmitARCDestroyWeak(field);
}
void profileImpl(llvm::FoldingSetNodeID &id) const {
// 0 is distinguishable from all pointers and byref flags
id.AddInteger(0);
}
};
/// Emits the copy/dispose helpers for an ARC __block __strong variable
/// that's not of block-pointer type.
class ARCStrongByrefHelpers : public CodeGenModule::ByrefHelpers {
public:
ARCStrongByrefHelpers(CharUnits alignment) : ByrefHelpers(alignment) {}
void emitCopy(CodeGenFunction &CGF, llvm::Value *destField,
llvm::Value *srcField) {
// Do a "move" by copying the value and then zeroing out the old
// variable.
llvm::Value *value = CGF.Builder.CreateLoad(srcField);
llvm::Value *null =
llvm::ConstantPointerNull::get(cast<llvm::PointerType>(value->getType()));
CGF.Builder.CreateStore(value, destField);
CGF.Builder.CreateStore(null, srcField);
}
void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
llvm::Value *value = CGF.Builder.CreateLoad(field);
CGF.EmitARCRelease(value, /*precise*/ false);
}
void profileImpl(llvm::FoldingSetNodeID &id) const {
// 1 is distinguishable from all pointers and byref flags
id.AddInteger(1);
}
};
/// Emits the copy/dispose helpers for a __block variable with a
/// nontrivial copy constructor or destructor.
class CXXByrefHelpers : public CodeGenModule::ByrefHelpers {
@ -1318,6 +1436,7 @@ generateByrefCopyHelper(CodeGenFunction &CGF,
SC_Static,
SC_None,
false, true);
CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation());
if (byrefInfo.needsCopy()) {
@ -1449,6 +1568,52 @@ CodeGenFunction::buildByrefHelpers(const llvm::StructType &byrefType,
return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
}
// Otherwise, if we don't have a retainable type, there's nothing to do.
// that the runtime does extra copies.
if (!type->isObjCRetainableType()) return 0;
Qualifiers qs = type.getQualifiers();
// If we have lifetime, that dominates.
if (Qualifiers::ObjCLifetime lifetime = qs.getObjCLifetime()) {
assert(getLangOptions().ObjCAutoRefCount);
switch (lifetime) {
case Qualifiers::OCL_None: llvm_unreachable("impossible");
// These are just bits as far as the runtime is concerned.
case Qualifiers::OCL_ExplicitNone:
case Qualifiers::OCL_Autoreleasing:
return 0;
// Tell the runtime that this is ARC __weak, called by the
// byref routines.
case Qualifiers::OCL_Weak: {
ARCWeakByrefHelpers byrefInfo(emission.Alignment);
return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
}
// ARC __strong __block variables need to be retained.
case Qualifiers::OCL_Strong:
// Block-pointers need to be _Block_copy'ed, so we let the
// runtime be in charge. But we can't use the code below
// because we don't want to set BYREF_CALLER, which will
// just make the runtime ignore us.
if (type->isBlockPointerType()) {
BlockFieldFlags flags = BLOCK_FIELD_IS_BLOCK;
ObjectByrefHelpers byrefInfo(emission.Alignment, flags);
return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
// Otherwise, we transfer ownership of the retain from the stack
// to the heap.
} else {
ARCStrongByrefHelpers byrefInfo(emission.Alignment);
return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
}
}
llvm_unreachable("fell out of lifetime switch!");
}
BlockFieldFlags flags;
if (type->isBlockPointerType()) {
flags |= BLOCK_FIELD_IS_BLOCK;
@ -1639,6 +1804,7 @@ namespace {
CallBlockRelease(llvm::Value *Addr) : Addr(Addr) {}
void Emit(CodeGenFunction &CGF, bool IsForEH) {
// Should we be passing FIELD_IS_WEAK here?
CGF.BuildBlockRelease(Addr, BLOCK_FIELD_IS_BYREF);
}
};

View File

@ -89,7 +89,7 @@ enum BlockFieldFlag_t {
variable */
BLOCK_FIELD_IS_WEAK = 0x10, /* declared __weak, only used in byref copy
helpers */
BLOCK_FIELD_IS_ARC = 0x40, /* field has ARC-specific semantics */
BLOCK_BYREF_CALLER = 128, /* called from __block (byref) copy/dispose
support routines */
BLOCK_BYREF_CURRENT_MAX = 256

View File

@ -25,6 +25,7 @@
#include "llvm/Attributes.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Target/TargetData.h"
#include "llvm/InlineAsm.h"
#include "llvm/Transforms/Utils/Local.h"
using namespace clang;
using namespace CodeGen;
@ -190,13 +191,15 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) {
e = MD->param_end(); i != e; ++i) {
ArgTys.push_back(Context.getCanonicalParamType((*i)->getType()));
}
return getFunctionInfo(GetReturnType(MD->getResultType()),
ArgTys,
FunctionType::ExtInfo(
/*NoReturn*/ false,
/*HasRegParm*/ false,
/*RegParm*/ 0,
getCallingConventionForDecl(MD)));
FunctionType::ExtInfo einfo;
einfo = einfo.withCallingConv(getCallingConventionForDecl(MD));
if (getContext().getLangOptions().ObjCAutoRefCount &&
MD->hasAttr<NSReturnsRetainedAttr>())
einfo = einfo.withProducesResult(true);
return getFunctionInfo(GetReturnType(MD->getResultType()), ArgTys, einfo);
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(GlobalDecl GD) {
@ -262,7 +265,8 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
return *FI;
// Construct the function info.
FI = new CGFunctionInfo(CC, Info.getNoReturn(), Info.getHasRegParm(), Info.getRegParm(), ResTy,
FI = new CGFunctionInfo(CC, Info.getNoReturn(), Info.getProducesResult(),
Info.getHasRegParm(), Info.getRegParm(), ResTy,
ArgTys.data(), ArgTys.size());
FunctionInfos.InsertNode(FI, InsertPos);
@ -291,13 +295,15 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
}
CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention,
bool _NoReturn, bool _HasRegParm, unsigned _RegParm,
bool _NoReturn, bool returnsRetained,
bool _HasRegParm, unsigned _RegParm,
CanQualType ResTy,
const CanQualType *ArgTys,
unsigned NumArgTys)
: CallingConvention(_CallingConvention),
EffectiveCallingConvention(_CallingConvention),
NoReturn(_NoReturn), HasRegParm(_HasRegParm), RegParm(_RegParm)
NoReturn(_NoReturn), ReturnsRetained(returnsRetained),
HasRegParm(_HasRegParm), RegParm(_RegParm)
{
NumArgs = NumArgTys;
@ -1068,6 +1074,95 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
assert(AI == Fn->arg_end() && "Argument mismatch!");
}
/// Try to emit a fused autorelease of a return result.
static llvm::Value *tryEmitFusedAutoreleaseOfResult(CodeGenFunction &CGF,
llvm::Value *result) {
// We must be immediately followed the cast.
llvm::BasicBlock *BB = CGF.Builder.GetInsertBlock();
if (BB->empty()) return 0;
if (&BB->back() != result) return 0;
const llvm::Type *resultType = result->getType();
// result is in a BasicBlock and is therefore an Instruction.
llvm::Instruction *generator = cast<llvm::Instruction>(result);
llvm::SmallVector<llvm::Instruction*,4> insnsToKill;
// Look for:
// %generator = bitcast %type1* %generator2 to %type2*
while (llvm::BitCastInst *bitcast = dyn_cast<llvm::BitCastInst>(generator)) {
// We would have emitted this as a constant if the operand weren't
// an Instruction.
generator = cast<llvm::Instruction>(bitcast->getOperand(0));
// Require the generator to be immediately followed by the cast.
if (generator->getNextNode() != bitcast)
return 0;
insnsToKill.push_back(bitcast);
}
// Look for:
// %generator = call i8* @objc_retain(i8* %originalResult)
// or
// %generator = call i8* @objc_retainAutoreleasedReturnValue(i8* %originalResult)
llvm::CallInst *call = dyn_cast<llvm::CallInst>(generator);
if (!call) return 0;
bool doRetainAutorelease;
if (call->getCalledValue() == CGF.CGM.getARCEntrypoints().objc_retain) {
doRetainAutorelease = true;
} else if (call->getCalledValue() == CGF.CGM.getARCEntrypoints()
.objc_retainAutoreleasedReturnValue) {
doRetainAutorelease = false;
// Look for an inline asm immediately preceding the call and kill it, too.
llvm::Instruction *prev = call->getPrevNode();
if (llvm::CallInst *asmCall = dyn_cast_or_null<llvm::CallInst>(prev))
if (asmCall->getCalledValue()
== CGF.CGM.getARCEntrypoints().retainAutoreleasedReturnValueMarker)
insnsToKill.push_back(prev);
} else {
return 0;
}
result = call->getArgOperand(0);
insnsToKill.push_back(call);
// Keep killing bitcasts, for sanity. Note that we no longer care
// about precise ordering as long as there's exactly one use.
while (llvm::BitCastInst *bitcast = dyn_cast<llvm::BitCastInst>(result)) {
if (!bitcast->hasOneUse()) break;
insnsToKill.push_back(bitcast);
result = bitcast->getOperand(0);
}
// Delete all the unnecessary instructions, from latest to earliest.
for (llvm::SmallVectorImpl<llvm::Instruction*>::iterator
i = insnsToKill.begin(), e = insnsToKill.end(); i != e; ++i)
(*i)->eraseFromParent();
// Do the fused retain/autorelease if we were asked to.
if (doRetainAutorelease)
result = CGF.EmitARCRetainAutoreleaseReturnValue(result);
// Cast back to the result type.
return CGF.Builder.CreateBitCast(result, resultType);
}
/// Emit an ARC autorelease of the result of a function.
static llvm::Value *emitAutoreleaseOfResult(CodeGenFunction &CGF,
llvm::Value *result) {
// At -O0, try to emit a fused retain/autorelease.
if (CGF.shouldUseFusedARCCalls())
if (llvm::Value *fused = tryEmitFusedAutoreleaseOfResult(CGF, result))
return fused;
return CGF.EmitARCAutoreleaseReturnValue(result);
}
void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
// Functions with no result always return void.
if (ReturnValue == 0) {
@ -1135,6 +1230,16 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
RV = CreateCoercedLoad(V, RetAI.getCoerceToType(), *this);
}
// In ARC, end functions that return a retainable type with a call
// to objc_autoreleaseReturnValue.
if (AutoreleaseResult) {
assert(getLangOptions().ObjCAutoRefCount &&
!FI.isReturnsRetained() &&
RetTy->isObjCRetainableType());
RV = emitAutoreleaseOfResult(*this, RV);
}
break;
case ABIArgInfo::Ignore:
@ -1184,8 +1289,152 @@ void CodeGenFunction::EmitDelegateCallArg(CallArgList &args,
return args.add(RValue::get(value), type);
}
static bool isProvablyNull(llvm::Value *addr) {
return isa<llvm::ConstantPointerNull>(addr);
}
static bool isProvablyNonNull(llvm::Value *addr) {
return isa<llvm::AllocaInst>(addr);
}
/// Emit the actual writing-back of a writeback.
static void emitWriteback(CodeGenFunction &CGF,
const CallArgList::Writeback &writeback) {
llvm::Value *srcAddr = writeback.Address;
assert(!isProvablyNull(srcAddr) &&
"shouldn't have writeback for provably null argument");
llvm::BasicBlock *contBB = 0;
// If the argument wasn't provably non-null, we need to null check
// before doing the store.
bool provablyNonNull = isProvablyNonNull(srcAddr);
if (!provablyNonNull) {
llvm::BasicBlock *writebackBB = CGF.createBasicBlock("icr.writeback");
contBB = CGF.createBasicBlock("icr.done");
llvm::Value *isNull = CGF.Builder.CreateIsNull(srcAddr, "icr.isnull");
CGF.Builder.CreateCondBr(isNull, contBB, writebackBB);
CGF.EmitBlock(writebackBB);
}
// Load the value to writeback.
llvm::Value *value = CGF.Builder.CreateLoad(writeback.Temporary);
// Cast it back, in case we're writing an id to a Foo* or something.
value = CGF.Builder.CreateBitCast(value,
cast<llvm::PointerType>(srcAddr->getType())->getElementType(),
"icr.writeback-cast");
// Perform the writeback.
QualType srcAddrType = writeback.AddressType;
CGF.EmitStoreThroughLValue(RValue::get(value),
CGF.MakeAddrLValue(srcAddr, srcAddrType),
srcAddrType);
// Jump to the continuation block.
if (!provablyNonNull)
CGF.EmitBlock(contBB);
}
static void emitWritebacks(CodeGenFunction &CGF,
const CallArgList &args) {
for (CallArgList::writeback_iterator
i = args.writeback_begin(), e = args.writeback_end(); i != e; ++i)
emitWriteback(CGF, *i);
}
/// Emit an argument that's being passed call-by-writeback. That is,
/// we are passing the address of
static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
const ObjCIndirectCopyRestoreExpr *CRE) {
llvm::Value *srcAddr = CGF.EmitScalarExpr(CRE->getSubExpr());
// The dest and src types don't necessarily match in LLVM terms
// because of the crazy ObjC compatibility rules.
const llvm::PointerType *destType =
cast<llvm::PointerType>(CGF.ConvertType(CRE->getType()));
// If the address is a constant null, just pass the appropriate null.
if (isProvablyNull(srcAddr)) {
args.add(RValue::get(llvm::ConstantPointerNull::get(destType)),
CRE->getType());
return;
}
QualType srcAddrType =
CRE->getSubExpr()->getType()->castAs<PointerType>()->getPointeeType();
// Create the temporary.
llvm::Value *temp = CGF.CreateTempAlloca(destType->getElementType(),
"icr.temp");
// Zero-initialize it if we're not doing a copy-initialization.
bool shouldCopy = CRE->shouldCopy();
if (!shouldCopy) {
llvm::Value *null =
llvm::ConstantPointerNull::get(
cast<llvm::PointerType>(destType->getElementType()));
CGF.Builder.CreateStore(null, temp);
}
llvm::BasicBlock *contBB = 0;
// If the address is *not* known to be non-null, we need to switch.
llvm::Value *finalArgument;
bool provablyNonNull = isProvablyNonNull(srcAddr);
if (provablyNonNull) {
finalArgument = temp;
} else {
llvm::Value *isNull = CGF.Builder.CreateIsNull(srcAddr, "icr.isnull");
finalArgument = CGF.Builder.CreateSelect(isNull,
llvm::ConstantPointerNull::get(destType),
temp, "icr.argument");
// If we need to copy, then the load has to be conditional, which
// means we need control flow.
if (shouldCopy) {
contBB = CGF.createBasicBlock("icr.cont");
llvm::BasicBlock *copyBB = CGF.createBasicBlock("icr.copy");
CGF.Builder.CreateCondBr(isNull, contBB, copyBB);
CGF.EmitBlock(copyBB);
}
}
// Perform a copy if necessary.
if (shouldCopy) {
LValue srcLV = CGF.MakeAddrLValue(srcAddr, srcAddrType);
RValue srcRV = CGF.EmitLoadOfLValue(srcLV, srcAddrType);
assert(srcRV.isScalar());
llvm::Value *src = srcRV.getScalarVal();
src = CGF.Builder.CreateBitCast(src, destType->getElementType(),
"icr.cast");
// Use an ordinary store, not a store-to-lvalue.
CGF.Builder.CreateStore(src, temp);
}
// Finish the control flow if we needed it.
if (shouldCopy && !provablyNonNull)
CGF.EmitBlock(contBB);
args.addWriteback(srcAddr, srcAddrType, temp);
args.add(RValue::get(finalArgument), CRE->getType());
}
void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
QualType type) {
if (const ObjCIndirectCopyRestoreExpr *CRE
= dyn_cast<ObjCIndirectCopyRestoreExpr>(E)) {
assert(getContext().getLangOptions().ObjCAutoRefCount);
assert(getContext().hasSameType(E->getType(), type));
return emitWritebackArg(*this, args, CRE);
}
if (type->isReferenceType())
return args.add(EmitReferenceBindingToExpr(E, /*InitializedDecl=*/0),
type);
@ -1435,6 +1684,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
if (Builder.isNamePreserving() && !CI->getType()->isVoidTy())
CI->setName("call");
// Emit any writebacks immediately. Arguably this should happen
// after any return-value munging.
if (CallArgs.hasWritebacks())
emitWritebacks(*this, CallArgs);
switch (RetAI.getKind()) {
case ABIArgInfo::Indirect: {
unsigned Alignment = getContext().getTypeAlignInChars(RetTy).getQuantity();

View File

@ -58,9 +58,44 @@ namespace CodeGen {
class CallArgList :
public llvm::SmallVector<CallArg, 16> {
public:
struct Writeback {
/// The original argument.
llvm::Value *Address;
/// The pointee type of the original argument.
QualType AddressType;
/// The temporary alloca.
llvm::Value *Temporary;
};
void add(RValue rvalue, QualType type, bool needscopy = false) {
push_back(CallArg(rvalue, type, needscopy));
}
void addFrom(const CallArgList &other) {
insert(end(), other.begin(), other.end());
Writebacks.insert(Writebacks.end(),
other.Writebacks.begin(), other.Writebacks.end());
}
void addWriteback(llvm::Value *address, QualType addressType,
llvm::Value *temporary) {
Writeback writeback;
writeback.Address = address;
writeback.AddressType = addressType;
writeback.Temporary = temporary;
Writebacks.push_back(writeback);
}
bool hasWritebacks() const { return !Writebacks.empty(); }
typedef llvm::SmallVectorImpl<Writeback>::const_iterator writeback_iterator;
writeback_iterator writeback_begin() const { return Writebacks.begin(); }
writeback_iterator writeback_end() const { return Writebacks.end(); }
private:
llvm::SmallVector<Writeback, 1> Writebacks;
};
/// FunctionArgList - Type for representing both the decl and type
@ -88,6 +123,9 @@ namespace CodeGen {
/// Whether this function is noreturn.
bool NoReturn;
/// Whether this function is returns-retained.
bool ReturnsRetained;
unsigned NumArgs;
ArgInfo *Args;
@ -100,7 +138,8 @@ namespace CodeGen {
typedef ArgInfo *arg_iterator;
CGFunctionInfo(unsigned CallingConvention, bool NoReturn,
bool HasRegParm, unsigned RegParm, CanQualType ResTy,
bool ReturnsRetained, bool HasRegParm, unsigned RegParm,
CanQualType ResTy,
const CanQualType *ArgTys, unsigned NumArgTys);
~CGFunctionInfo() { delete[] Args; }
@ -113,6 +152,10 @@ namespace CodeGen {
bool isNoReturn() const { return NoReturn; }
/// In ARR, whether this function retains its return value. This
/// is not always reliable for call sites.
bool isReturnsRetained() const { return ReturnsRetained; }
/// getCallingConvention - Return the user specified calling
/// convention.
unsigned getCallingConvention() const { return CallingConvention; }
@ -137,6 +180,7 @@ namespace CodeGen {
void Profile(llvm::FoldingSetNodeID &ID) {
ID.AddInteger(getCallingConvention());
ID.AddBoolean(NoReturn);
ID.AddBoolean(ReturnsRetained);
ID.AddBoolean(HasRegParm);
ID.AddInteger(RegParm);
getReturnType().Profile(ID);
@ -151,6 +195,7 @@ namespace CodeGen {
Iterator end) {
ID.AddInteger(Info.getCC());
ID.AddBoolean(Info.getNoReturn());
ID.AddBoolean(Info.getProducesResult());
ID.AddBoolean(Info.getHasRegParm());
ID.AddInteger(Info.getRegParm());
ResTy.Profile(ID);

View File

@ -398,7 +398,8 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
BaseClassDecl,
isBaseVirtual);
AggValueSlot AggSlot = AggValueSlot::forAddr(V, false, /*Lifetime*/ true);
AggValueSlot AggSlot = AggValueSlot::forAddr(V, Qualifiers(),
/*Lifetime*/ true);
CGF.EmitAggExpr(BaseInit->getInit(), AggSlot);
@ -428,10 +429,20 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF,
CGF.Builder.CreateStore(Next, ArrayIndexVar);
}
AggValueSlot Slot = AggValueSlot::forAddr(Dest, LHS.isVolatileQualified(),
/*Lifetime*/ true);
CGF.EmitAggExpr(MemberInit->getInit(), Slot);
if (!CGF.hasAggregateLLVMType(T)) {
CGF.EmitScalarInit(MemberInit->getInit(), 0, Dest, false,
LHS.isVolatileQualified(),
CGF.getContext().getTypeAlign(T),
T);
} else if (T->isAnyComplexType()) {
CGF.EmitComplexExprIntoAddr(MemberInit->getInit(), Dest,
LHS.isVolatileQualified());
} else {
AggValueSlot Slot = AggValueSlot::forAddr(Dest, LHS.getQuals(),
/*Lifetime*/ true);
CGF.EmitAggExpr(MemberInit->getInit(), Slot);
}
return;
}
@ -540,15 +551,16 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
// FIXME: If there's no initializer and the CXXCtorInitializer
// was implicitly generated, we shouldn't be zeroing memory.
RValue RHS;
if (FieldType->isReferenceType()) {
RHS = CGF.EmitReferenceBindingToExpr(MemberInit->getInit(), Field);
CGF.EmitStoreThroughLValue(RHS, LHS, FieldType);
} else if (FieldType->isArrayType() && !MemberInit->getInit()) {
if (FieldType->isArrayType() && !MemberInit->getInit()) {
CGF.EmitNullInitialization(LHS.getAddress(), Field->getType());
} else if (!CGF.hasAggregateLLVMType(Field->getType())) {
RHS = RValue::get(CGF.EmitScalarExpr(MemberInit->getInit()));
CGF.EmitStoreThroughLValue(RHS, LHS, FieldType);
if (LHS.isSimple()) {
CGF.EmitExprAsInit(MemberInit->getInit(), Field, LHS.getAddress(),
CGF.getContext().getDeclAlign(Field), false);
} else {
RValue RHS = RValue::get(CGF.EmitScalarExpr(MemberInit->getInit()));
CGF.EmitStoreThroughLValue(RHS, LHS, FieldType);
}
} else if (MemberInit->getInit()->getType()->isAnyComplexType()) {
CGF.EmitComplexExprIntoAddr(MemberInit->getInit(), LHS.getAddress(),
LHS.isVolatileQualified());
@ -576,11 +588,11 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
llvm::Value *Zero = llvm::Constant::getNullValue(SizeTy);
CGF.Builder.CreateStore(Zero, ArrayIndexVar);
// If we are copying an array of scalars or classes with trivial copy
// If we are copying an array of PODs or classes with trivial copy
// constructors, perform a single aggregate copy.
const RecordType *Record = BaseElementTy->getAs<RecordType>();
if (!Record ||
cast<CXXRecordDecl>(Record->getDecl())->hasTrivialCopyConstructor()) {
const CXXRecordDecl *Record = BaseElementTy->getAsCXXRecordDecl();
if (BaseElementTy.isPODType(CGF.getContext()) ||
(Record && Record->hasTrivialCopyConstructor())) {
// Find the source pointer. We knows it's the last argument because
// we know we're in a copy constructor.
unsigned SrcArgIndex = Args.size() - 1;
@ -925,12 +937,8 @@ namespace {
CallArrayFieldDtor(const FieldDecl *Field) : Field(Field) {}
void Emit(CodeGenFunction &CGF, bool IsForEH) {
QualType FieldType = Field->getType();
const ConstantArrayType *Array =
CGF.getContext().getAsConstantArrayType(FieldType);
QualType BaseType =
CGF.getContext().getBaseElementType(Array->getElementType());
QualType FieldType = Field->getType();
QualType BaseType = CGF.getContext().getBaseElementType(FieldType);
const CXXRecordDecl *FieldClassDecl = BaseType->getAsCXXRecordDecl();
llvm::Value *ThisPtr = CGF.LoadCXXThis();
@ -938,9 +946,12 @@ namespace {
// FIXME: Qualifiers?
/*CVRQualifiers=*/0);
const llvm::Type *BasePtr = CGF.ConvertType(BaseType)->getPointerTo();
llvm::Value *BaseAddrPtr =
CGF.Builder.CreateBitCast(LHS.getAddress(), BasePtr);
const llvm::Type *BasePtr
= CGF.ConvertType(BaseType)->getPointerTo();
llvm::Value *BaseAddrPtr
= CGF.Builder.CreateBitCast(LHS.getAddress(), BasePtr);
const ConstantArrayType *Array
= CGF.getContext().getAsConstantArrayType(FieldType);
CGF.EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(),
Array, BaseAddrPtr);
}
@ -1042,19 +1053,26 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
getContext().getAsConstantArrayType(FieldType);
if (Array)
FieldType = getContext().getBaseElementType(Array->getElementType());
const RecordType *RT = FieldType->getAs<RecordType>();
if (!RT)
continue;
CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
if (FieldClassDecl->hasTrivialDestructor())
continue;
if (Array)
EHStack.pushCleanup<CallArrayFieldDtor>(NormalAndEHCleanup, Field);
else
EHStack.pushCleanup<CallFieldDtor>(NormalAndEHCleanup, Field);
switch (FieldType.isDestructedType()) {
case QualType::DK_none:
continue;
case QualType::DK_cxx_destructor:
if (Array)
EHStack.pushCleanup<CallArrayFieldDtor>(NormalAndEHCleanup, Field);
else
EHStack.pushCleanup<CallFieldDtor>(NormalAndEHCleanup, Field);
break;
case QualType::DK_objc_strong_lifetime:
PushARCFieldReleaseCleanup(getARCCleanupKind(), Field);
break;
case QualType::DK_objc_weak_lifetime:
PushARCFieldWeakReleaseCleanup(getARCCleanupKind(), Field);
break;
}
}
}
@ -1384,7 +1402,8 @@ CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor
llvm::Value *ThisPtr = LoadCXXThis();
AggValueSlot AggSlot = AggValueSlot::forAddr(ThisPtr, false, /*Lifetime*/ true);
AggValueSlot AggSlot =
AggValueSlot::forAddr(ThisPtr, Qualifiers(), /*Lifetime*/ true);
EmitAggExpr(Ctor->init_begin()[0]->getInit(), AggSlot);

View File

@ -389,6 +389,7 @@ llvm::DIType CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DIFile Unit) {
// Ignore these qualifiers for now.
Qc.removeObjCGCAttr();
Qc.removeAddressSpace();
Qc.removeObjCLifetime();
// We will create one Derived type for one qualifier and recurse to handle any
// additional ones.

View File

@ -353,9 +353,7 @@ namespace {
if (NRVO) CGF.EmitBlock(SkipDtorBB);
}
};
}
namespace {
struct CallStackRestore : EHScopeStack::Cleanup {
llvm::Value *Stack;
CallStackRestore(llvm::Value *Stack) : Stack(Stack) {}
@ -400,6 +398,164 @@ namespace {
};
}
/// EmitAutoVarWithLifetime - Does the setup required for an automatic
/// variable with lifetime.
static void EmitAutoVarWithLifetime(CodeGenFunction &CGF, const VarDecl &var,
llvm::Value *addr,
Qualifiers::ObjCLifetime lifetime) {
switch (lifetime) {
case Qualifiers::OCL_None:
llvm_unreachable("present but none");
case Qualifiers::OCL_ExplicitNone:
// nothing to do
break;
case Qualifiers::OCL_Strong: {
CGF.PushARCReleaseCleanup(CGF.getARCCleanupKind(),
var.getType(), addr,
var.hasAttr<ObjCPreciseLifetimeAttr>());
break;
}
case Qualifiers::OCL_Autoreleasing:
// nothing to do
break;
case Qualifiers::OCL_Weak:
// __weak objects always get EH cleanups; otherwise, exceptions
// could cause really nasty crashes instead of mere leaks.
CGF.PushARCWeakReleaseCleanup(NormalAndEHCleanup, var.getType(), addr);
break;
}
}
static bool isAccessedBy(const VarDecl &var, const Stmt *s) {
if (const Expr *e = dyn_cast<Expr>(s)) {
// Skip the most common kinds of expressions that make
// hierarchy-walking expensive.
s = e = e->IgnoreParenCasts();
if (const DeclRefExpr *ref = dyn_cast<DeclRefExpr>(e))
return (ref->getDecl() == &var);
}
for (Stmt::const_child_range children = s->children(); children; ++children)
if (isAccessedBy(var, *children))
return true;
return false;
}
static bool isAccessedBy(const ValueDecl *decl, const Expr *e) {
if (!decl) return false;
if (!isa<VarDecl>(decl)) return false;
const VarDecl *var = cast<VarDecl>(decl);
return isAccessedBy(*var, e);
}
void CodeGenFunction::EmitScalarInit(const Expr *init,
const ValueDecl *D,
llvm::Value *addr, bool capturedByInit,
bool isVolatile, unsigned alignment,
QualType type) {
Qualifiers::ObjCLifetime lifetime = type.getQualifiers().getObjCLifetime();
if (!lifetime) {
llvm::Value *value = EmitScalarExpr(init);
if (capturedByInit) addr = BuildBlockByrefAddress(addr, cast<VarDecl>(D));
EmitStoreOfScalar(value, addr, isVolatile, alignment, type);
return;
}
// If we're emitting a value with lifetime, we have to do the
// initialization *before* we leave the cleanup scopes.
CodeGenFunction::RunCleanupsScope Scope(*this);
if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(init))
init = ewc->getSubExpr();
// We have to maintain the illusion that the variable is
// zero-initialized. If the variable might be accessed in its
// initializer, zero-initialize before running the initializer, then
// actually perform the initialization with an assign.
bool accessedByInit = false;
if (lifetime != Qualifiers::OCL_ExplicitNone)
accessedByInit = isAccessedBy(D, init);
if (accessedByInit) {
// Drill down to the __block object if necessary.
llvm::Value *tempAddr = addr;
if (capturedByInit) {
// We can use a simple GEP for this because it can't have been
// moved yet.
tempAddr = Builder.CreateStructGEP(tempAddr,
getByRefValueLLVMField(cast<VarDecl>(D)));
}
const llvm::PointerType *ty = cast<llvm::PointerType>(tempAddr->getType());
ty = cast<llvm::PointerType>(ty->getElementType());
llvm::Value *zero = llvm::ConstantPointerNull::get(ty);
// If __weak, we want to use a barrier under certain conditions.
if (lifetime == Qualifiers::OCL_Weak)
EmitARCInitWeak(tempAddr, zero);
// Otherwise just do a simple store.
else
EmitStoreOfScalar(zero, tempAddr, isVolatile, alignment, type);
}
// Emit the initializer.
llvm::Value *value = 0;
switch (lifetime) {
case Qualifiers::OCL_None:
llvm_unreachable("present but none");
case Qualifiers::OCL_ExplicitNone:
// nothing to do
value = EmitScalarExpr(init);
break;
case Qualifiers::OCL_Strong: {
value = EmitARCRetainScalarExpr(init);
break;
}
case Qualifiers::OCL_Weak: {
// No way to optimize a producing initializer into this. It's not
// worth optimizing for, because the value will immediately
// disappear in the common case.
value = EmitScalarExpr(init);
if (capturedByInit) addr = BuildBlockByrefAddress(addr, cast<VarDecl>(D));
if (accessedByInit)
EmitARCStoreWeak(addr, value, /*ignored*/ true);
else
EmitARCInitWeak(addr, value);
return;
}
case Qualifiers::OCL_Autoreleasing:
value = EmitARCRetainAutoreleaseScalarExpr(init);
break;
}
if (capturedByInit) addr = BuildBlockByrefAddress(addr, cast<VarDecl>(D));
llvm::MDNode *tbaa = CGM.getTBAAInfo(type);
// If the variable might have been accessed by its initializer, we
// might have to initialize with a barrier. We have to do this for
// both __weak and __strong, but __weak got filtered out above.
if (accessedByInit && lifetime == Qualifiers::OCL_Strong) {
llvm::Value *oldValue
= EmitLoadOfScalar(addr, isVolatile, alignment, type, tbaa);
EmitStoreOfScalar(value, addr, isVolatile, alignment, type, tbaa);
EmitARCRelease(oldValue, /*precise*/ false);
return;
}
EmitStoreOfScalar(value, addr, isVolatile, alignment, type, tbaa);
}
/// canEmitInitWithFewStoresAfterMemset - Decide whether we can emit the
/// non-zero parts of the specified initializer with equal or fewer than
@ -521,7 +677,9 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
// arrays as long as the initialization is trivial (e.g. if they
// have a non-trivial destructor, but not a non-trivial constructor).
if (D.getInit() &&
(Ty->isArrayType() || Ty->isRecordType()) && Ty->isPODType() &&
(Ty->isArrayType() || Ty->isRecordType()) &&
(Ty.isPODType(getContext()) ||
getContext().getBaseElementType(Ty)->isObjCObjectPointerType()) &&
D.getInit()->isConstantInitializer(getContext(), false)) {
// If the variable's a const type, and it's neither an NRVO
@ -765,29 +923,30 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
/// \param capturedByInit true if the variable is a __block variable
/// whose address is potentially changed by the initializer
void CodeGenFunction::EmitExprAsInit(const Expr *init,
const VarDecl *var,
const ValueDecl *D,
llvm::Value *loc,
CharUnits alignment,
bool capturedByInit) {
QualType type = var->getType();
QualType type = D->getType();
bool isVolatile = type.isVolatileQualified();
if (type->isReferenceType()) {
RValue RV = EmitReferenceBindingToExpr(init, var);
if (capturedByInit) loc = BuildBlockByrefAddress(loc, var);
RValue RV = EmitReferenceBindingToExpr(init, D);
if (capturedByInit)
loc = BuildBlockByrefAddress(loc, cast<VarDecl>(D));
EmitStoreOfScalar(RV.getScalarVal(), loc, false,
alignment.getQuantity(), type);
} else if (!hasAggregateLLVMType(type)) {
llvm::Value *V = EmitScalarExpr(init);
if (capturedByInit) loc = BuildBlockByrefAddress(loc, var);
EmitStoreOfScalar(V, loc, isVolatile, alignment.getQuantity(), type);
EmitScalarInit(init, D, loc, capturedByInit, isVolatile,
alignment.getQuantity(), type);
} else if (type->isAnyComplexType()) {
ComplexPairTy complex = EmitComplexExpr(init);
if (capturedByInit) loc = BuildBlockByrefAddress(loc, var);
if (capturedByInit) loc = BuildBlockByrefAddress(loc, cast<VarDecl>(D));
StoreComplexToAddr(complex, loc, isVolatile);
} else {
// TODO: how can we delay here if D is captured by its initializer?
EmitAggExpr(init, AggValueSlot::forAddr(loc, isVolatile, true, false));
EmitAggExpr(init, AggValueSlot::forAddr(loc, type.getQualifiers(), true,
false));
}
}
@ -799,7 +958,7 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
const VarDecl &D = *emission.Variable;
// Handle C++ destruction of variables.
// Handle C++ or ARC destruction of variables.
if (getLangOptions().CPlusPlus) {
QualType type = D.getType();
QualType baseType = getContext().getBaseElementType(type);
@ -830,6 +989,12 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
}
}
if (Qualifiers::ObjCLifetime lifetime
= D.getType().getQualifiers().getObjCLifetime()) {
llvm::Value *loc = emission.getObjectAddress(*this);
EmitAutoVarWithLifetime(*this, D, loc, lifetime);
}
// Handle the cleanup attribute.
if (const CleanupAttr *CA = D.getAttr<CleanupAttr>()) {
const FunctionDecl *FD = CA->getFunctionDecl();
@ -847,6 +1012,22 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
enterByrefCleanup(emission);
}
namespace {
/// A cleanup to perform a release of an object at the end of a
/// function. This is used to balance out the incoming +1 of a
/// ns_consumed argument when we can't reasonably do that just by
/// not doing the initial retain for a __block argument.
struct ConsumeARCParameter : EHScopeStack::Cleanup {
ConsumeARCParameter(llvm::Value *param) : Param(param) {}
llvm::Value *Param;
void Emit(CodeGenFunction &CGF, bool IsForEH) {
CGF.EmitARCRelease(Param, /*precise*/ false);
}
};
}
/// Emit an alloca (or GlobalValue depending on target)
/// for the specified parameter and set up LocalDeclMap.
void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
@ -883,10 +1064,53 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
// Otherwise, create a temporary to hold the value.
DeclPtr = CreateMemTemp(Ty, D.getName() + ".addr");
bool doStore = true;
Qualifiers qs = Ty.getQualifiers();
if (Qualifiers::ObjCLifetime lt = qs.getObjCLifetime()) {
// We honor __attribute__((ns_consumed)) for types with lifetime.
// For __strong, it's handled by just skipping the initial retain;
// otherwise we have to balance out the initial +1 with an extra
// cleanup to do the release at the end of the function.
bool isConsumed = D.hasAttr<NSConsumedAttr>();
// 'self' is always formally __strong, but if this is not an
// init method then we don't want to retain it.
if (lt == Qualifiers::OCL_Strong && qs.hasConst() &&
isa<ImplicitParamDecl>(D)) {
const ObjCMethodDecl *method = cast<ObjCMethodDecl>(CurCodeDecl);
assert(&D == method->getSelfDecl());
assert(method->getMethodFamily() != OMF_init);
lt = Qualifiers::OCL_ExplicitNone;
}
if (lt == Qualifiers::OCL_Strong) {
if (!isConsumed)
// Don't use objc_retainBlock for block pointers, because we
// don't want to Block_copy something just because we got it
// as a parameter.
Arg = EmitARCRetainNonBlock(Arg);
} else {
// Push the cleanup for a consumed parameter.
if (isConsumed)
EHStack.pushCleanup<ConsumeARCParameter>(getARCCleanupKind(), Arg);
if (lt == Qualifiers::OCL_Weak) {
EmitARCInitWeak(DeclPtr, Arg);
doStore = false; // The weak init is a store, no need to do two
}
}
// Enter the cleanup scope.
EmitAutoVarWithLifetime(*this, D, DeclPtr, lt);
}
// Store the initial value into the alloca.
EmitStoreOfScalar(Arg, DeclPtr, Ty.isVolatileQualified(),
getContext().getDeclAlign(&D).getQuantity(), Ty,
CGM.getTBAAInfo(Ty));
if (doStore)
EmitStoreOfScalar(Arg, DeclPtr, Ty.isVolatileQualified(),
getContext().getDeclAlign(&D).getQuantity(), Ty,
CGM.getTBAAInfo(Ty));
}
llvm::Value *&DMEntry = LocalDeclMap[&D];

View File

@ -34,20 +34,22 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
unsigned Alignment = Context.getDeclAlign(&D).getQuantity();
if (!CGF.hasAggregateLLVMType(T)) {
llvm::Value *V = CGF.EmitScalarExpr(Init);
CodeGenModule &CGM = CGF.CGM;
Qualifiers::GC GCAttr = CGM.getContext().getObjCGCAttrKind(T);
if (GCAttr == Qualifiers::Strong)
CGM.getObjCRuntime().EmitObjCGlobalAssign(CGF, V, DeclPtr,
D.isThreadSpecified());
CGM.getObjCRuntime().EmitObjCGlobalAssign(CGF, CGF.EmitScalarExpr(Init),
DeclPtr, D.isThreadSpecified());
else if (GCAttr == Qualifiers::Weak)
CGM.getObjCRuntime().EmitObjCWeakAssign(CGF, V, DeclPtr);
CGM.getObjCRuntime().EmitObjCWeakAssign(CGF, CGF.EmitScalarExpr(Init),
DeclPtr);
else
CGF.EmitStoreOfScalar(V, DeclPtr, isVolatile, Alignment, T);
CGF.EmitScalarInit(Init, &D, DeclPtr, false, isVolatile, Alignment,
D.getType());
} else if (T->isAnyComplexType()) {
CGF.EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile);
} else {
CGF.EmitAggExpr(Init, AggValueSlot::forAddr(DeclPtr, isVolatile, true));
CGF.EmitAggExpr(Init, AggValueSlot::forAddr(DeclPtr, T.getQualifiers(),
true));
}
}
@ -291,10 +293,21 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
getTypes().getNullaryFunctionInfo(),
FunctionArgList(), SourceLocation());
RunCleanupsScope Scope(*this);
// When building in Objective-C++ ARC mode, create an autorelease pool
// around the global initializers.
if (getLangOptions().ObjCAutoRefCount && getLangOptions().CPlusPlus) {
llvm::Value *token = EmitObjCAutoreleasePoolPush();
EmitObjCAutoreleasePoolCleanup(token);
}
for (unsigned i = 0; i != NumDecls; ++i)
if (Decls[i])
Builder.CreateCall(Decls[i]);
Builder.CreateCall(Decls[i]);
Scope.ForceCleanup();
FinishFunction();
}

View File

@ -354,7 +354,8 @@ static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *e,
// evaluated but before the exception is caught. But the best way
// to handle that is to teach EmitAggExpr to do the final copy
// differently if it can't be elided.
CGF.EmitAnyExprToMem(e, typedAddr, /*Volatile*/ false, /*IsInit*/ true);
CGF.EmitAnyExprToMem(e, typedAddr, e->getType().getQualifiers(),
/*IsInit*/ true);
// Deactivate the cleanup block.
CGF.DeactivateCleanupBlock(cleanup);
@ -1084,7 +1085,8 @@ static void InitCatchParam(CodeGenFunction &CGF,
CGF.EHStack.pushTerminate();
// Perform the copy construction.
CGF.EmitAggExpr(copyExpr, AggValueSlot::forAddr(ParamAddr, false, false));
CGF.EmitAggExpr(copyExpr, AggValueSlot::forAddr(ParamAddr, Qualifiers(),
false));
// Leave the terminate scope.
CGF.EHStack.popTerminate();

View File

@ -131,12 +131,12 @@ RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E) {
/// location.
void CodeGenFunction::EmitAnyExprToMem(const Expr *E,
llvm::Value *Location,
bool IsLocationVolatile,
Qualifiers Quals,
bool IsInit) {
if (E->getType()->isAnyComplexType())
EmitComplexExprIntoAddr(E, Location, IsLocationVolatile);
EmitComplexExprIntoAddr(E, Location, Quals.hasVolatile());
else if (hasAggregateLLVMType(E->getType()))
EmitAggExpr(E, AggValueSlot::forAddr(Location, IsLocationVolatile, IsInit));
EmitAggExpr(E, AggValueSlot::forAddr(Location, Quals, IsInit));
else {
RValue RV = RValue::get(EmitScalarExpr(E, /*Ignore*/ false));
LValue LV = MakeAddrLValue(Location, E->getType());
@ -203,7 +203,10 @@ static llvm::Value *
EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
llvm::Value *&ReferenceTemporary,
const CXXDestructorDecl *&ReferenceTemporaryDtor,
QualType &ObjCARCReferenceLifetimeType,
const NamedDecl *InitializedDecl) {
ObjCARCReferenceLifetimeType = QualType();
if (const CXXDefaultArgExpr *DAE = dyn_cast<CXXDefaultArgExpr>(E))
E = DAE->getExpr();
@ -213,6 +216,7 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
return EmitExprForReferenceBinding(CGF, TE->getSubExpr(),
ReferenceTemporary,
ReferenceTemporaryDtor,
ObjCARCReferenceLifetimeType,
InitializedDecl);
}
@ -279,12 +283,10 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
!E->getType()->isAnyComplexType()) {
ReferenceTemporary = CreateReferenceTemporary(CGF, E->getType(),
InitializedDecl);
AggSlot = AggValueSlot::forAddr(ReferenceTemporary, false,
AggSlot = AggValueSlot::forAddr(ReferenceTemporary, Qualifiers(),
InitializedDecl != 0);
}
RV = CGF.EmitAnyExpr(E, AggSlot);
if (InitializedDecl) {
// Get the destructor for the reference temporary.
if (const RecordType *RT = E->getType()->getAs<RecordType>()) {
@ -292,8 +294,37 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
if (!ClassDecl->hasTrivialDestructor())
ReferenceTemporaryDtor = ClassDecl->getDestructor();
}
else if (CGF.getContext().getLangOptions().ObjCAutoRefCount) {
if (const ValueDecl *InitVD = dyn_cast<ValueDecl>(InitializedDecl)) {
if (const ReferenceType *RefType
= InitVD->getType()->getAs<ReferenceType>()) {
QualType PointeeType = RefType->getPointeeType();
if (PointeeType->isObjCLifetimeType() &&
PointeeType.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) {
// Objective-C++ ARC: We're binding a reference to
// lifetime-qualified type to a temporary, so we need to extend
// the lifetime of the temporary with appropriate retain/release/
// autorelease calls.
ObjCARCReferenceLifetimeType = PointeeType;
// Create a temporary variable that we can bind the reference to.
ReferenceTemporary = CreateReferenceTemporary(CGF, PointeeType,
InitializedDecl);
unsigned Alignment =
CGF.getContext().getTypeAlignInChars(PointeeType).getQuantity();
CGF.EmitScalarInit(E, InitVD, ReferenceTemporary, false,
PointeeType.isVolatileQualified(),
Alignment, PointeeType);
return ReferenceTemporary;
}
}
}
}
}
RV = CGF.EmitAnyExpr(E, AggSlot);
// Check if need to perform derived-to-base casts and/or field accesses, to
// get from the temporary object we created (and, potentially, for which we
// extended the lifetime) to the subobject we're binding the reference to.
@ -361,26 +392,60 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E,
const NamedDecl *InitializedDecl) {
llvm::Value *ReferenceTemporary = 0;
const CXXDestructorDecl *ReferenceTemporaryDtor = 0;
QualType ObjCARCReferenceLifetimeType;
llvm::Value *Value = EmitExprForReferenceBinding(*this, E, ReferenceTemporary,
ReferenceTemporaryDtor,
ObjCARCReferenceLifetimeType,
InitializedDecl);
if (!ReferenceTemporaryDtor)
if (!ReferenceTemporaryDtor && ObjCARCReferenceLifetimeType.isNull())
return RValue::get(Value);
// Make sure to call the destructor for the reference temporary.
if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(InitializedDecl)) {
if (VD->hasGlobalStorage()) {
const VarDecl *VD = dyn_cast_or_null<VarDecl>(InitializedDecl);
if (VD && VD->hasGlobalStorage()) {
if (ReferenceTemporaryDtor) {
llvm::Constant *DtorFn =
CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete);
EmitCXXGlobalDtorRegistration(DtorFn,
cast<llvm::Constant>(ReferenceTemporary));
return RValue::get(Value);
} else {
assert(!ObjCARCReferenceLifetimeType.isNull());
// Note: We intentionally do not register a global "destructor" to
// release the object.
}
return RValue::get(Value);
}
PushDestructorCleanup(ReferenceTemporaryDtor, ReferenceTemporary);
if (ReferenceTemporaryDtor)
PushDestructorCleanup(ReferenceTemporaryDtor, ReferenceTemporary);
else {
switch (ObjCARCReferenceLifetimeType.getObjCLifetime()) {
case Qualifiers::OCL_None:
llvm_unreachable("Not a reference temporary that needs to be deallocated");
break;
case Qualifiers::OCL_ExplicitNone:
case Qualifiers::OCL_Autoreleasing:
// Nothing to do.
break;
case Qualifiers::OCL_Strong:
PushARCReleaseCleanup(getARCCleanupKind(), ObjCARCReferenceLifetimeType,
ReferenceTemporary,
VD && VD->hasAttr<ObjCPreciseLifetimeAttr>());
break;
case Qualifiers::OCL_Weak:
// __weak objects always get EH cleanups; otherwise, exceptions
// could cause really nasty crashes instead of mere leaks.
PushARCWeakReleaseCleanup(NormalAndEHCleanup,
ObjCARCReferenceLifetimeType,
ReferenceTemporary);
break;
}
}
return RValue::get(Value);
}
@ -599,6 +664,7 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
case Expr::CXXDynamicCastExprClass:
case Expr::CXXReinterpretCastExprClass:
case Expr::CXXConstCastExprClass:
case Expr::ObjCBridgedCastExprClass:
return EmitCastLValue(cast<CastExpr>(E));
}
}
@ -668,6 +734,8 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, QualType ExprType) {
return RValue::get(CGM.getObjCRuntime().EmitObjCWeakRead(*this,
AddrWeakObj));
}
if (LV.getQuals().getObjCLifetime() == Qualifiers::OCL_Weak)
return RValue::get(EmitARCLoadWeak(LV.getAddress()));
if (LV.isSimple()) {
llvm::Value *Ptr = LV.getAddress();
@ -838,6 +906,31 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
return EmitStoreThroughPropertyRefLValue(Src, Dst);
}
// There's special magic for assigning into an ARC-qualified l-value.
if (Qualifiers::ObjCLifetime Lifetime = Dst.getQuals().getObjCLifetime()) {
switch (Lifetime) {
case Qualifiers::OCL_None:
llvm_unreachable("present but none");
case Qualifiers::OCL_ExplicitNone:
// nothing special
break;
case Qualifiers::OCL_Strong:
EmitARCStoreStrong(Dst, Ty, Src.getScalarVal(), /*ignore*/ true);
return;
case Qualifiers::OCL_Weak:
EmitARCStoreWeak(Dst.getAddress(), Src.getScalarVal(), /*ignore*/ true);
return;
case Qualifiers::OCL_Autoreleasing:
Src = RValue::get(EmitObjCExtendObjectLifetime(Ty, Src.getScalarVal()));
// fall into the normal path
break;
}
}
if (Dst.isObjCWeak() && !Dst.isNonGC()) {
// load of a __weak object.
llvm::Value *LvalueDst = Dst.getAddress();
@ -1113,7 +1206,12 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV);
return;
}
if (const ObjCBridgedCastExpr *Exp = dyn_cast<ObjCBridgedCastExpr>(E)) {
setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV);
return;
}
if (const ArraySubscriptExpr *Exp = dyn_cast<ArraySubscriptExpr>(E)) {
setObjCGCLValueClass(Ctx, Exp->getBase(), LV);
if (LV.isObjCIvar() && !LV.isObjCArray())
@ -1734,7 +1832,8 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr *E){
const Expr *InitExpr = E->getInitializer();
LValue Result = MakeAddrLValue(DeclPtr, E->getType());
EmitAnyExprToMem(InitExpr, DeclPtr, /*Volatile*/ false, /*Init*/ true);
EmitAnyExprToMem(InitExpr, DeclPtr, E->getType().getQualifiers(),
/*Init*/ true);
return Result;
}
@ -1863,13 +1962,15 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_DerivedToBaseMemberPointer:
case CK_BaseToDerivedMemberPointer:
case CK_MemberPointerToBoolean:
case CK_AnyPointerToBlockPointerCast: {
case CK_AnyPointerToBlockPointerCast:
case CK_ObjCProduceObject:
case CK_ObjCConsumeObject: {
// These casts only produce lvalues when we're binding a reference to a
// temporary realized from a (converted) pure rvalue. Emit the expression
// as a value, copy it into a temporary, and return an lvalue referring to
// that temporary.
llvm::Value *V = CreateMemTemp(E->getType(), "ref.temp");
EmitAnyExprToMem(E, V, false, false);
EmitAnyExprToMem(E, V, E->getType().getQualifiers(), false);
return MakeAddrLValue(V, E->getType());
}
@ -1988,13 +2089,60 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(TargetDecl))
return EmitCXXOperatorMemberCallExpr(CE, MD, ReturnValue);
if (isa<CXXPseudoDestructorExpr>(E->getCallee()->IgnoreParens())) {
// C++ [expr.pseudo]p1:
// The result shall only be used as the operand for the function call
// operator (), and the result of such a call has type void. The only
// effect is the evaluation of the postfix-expression before the dot or
// arrow.
EmitScalarExpr(E->getCallee());
if (const CXXPseudoDestructorExpr *PseudoDtor
= dyn_cast<CXXPseudoDestructorExpr>(E->getCallee()->IgnoreParens())) {
QualType DestroyedType = PseudoDtor->getDestroyedType();
if (getContext().getLangOptions().ObjCAutoRefCount &&
DestroyedType->isObjCLifetimeType() &&
(DestroyedType.getObjCLifetime() == Qualifiers::OCL_Strong ||
DestroyedType.getObjCLifetime() == Qualifiers::OCL_Weak)) {
// Automatic Reference Counting:
// If the pseudo-expression names a retainable object with weak or strong
// lifetime, the object shall be released.
bool isNonGC = false;
Expr *BaseExpr = PseudoDtor->getBase();
llvm::Value *BaseValue = NULL;
Qualifiers BaseQuals;
// If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar.
if (PseudoDtor->isArrow()) {
BaseValue = EmitScalarExpr(BaseExpr);
const PointerType *PTy = BaseExpr->getType()->getAs<PointerType>();
BaseQuals = PTy->getPointeeType().getQualifiers();
} else {
LValue BaseLV = EmitLValue(BaseExpr);
if (BaseLV.isNonGC())
isNonGC = true;
BaseValue = BaseLV.getAddress();
QualType BaseTy = BaseExpr->getType();
BaseQuals = BaseTy.getQualifiers();
}
switch (PseudoDtor->getDestroyedType().getObjCLifetime()) {
case Qualifiers::OCL_None:
case Qualifiers::OCL_ExplicitNone:
case Qualifiers::OCL_Autoreleasing:
break;
case Qualifiers::OCL_Strong:
EmitARCRelease(Builder.CreateLoad(BaseValue,
PseudoDtor->getDestroyedType().isVolatileQualified()),
/*precise*/ true);
break;
case Qualifiers::OCL_Weak:
EmitARCDestroyWeak(BaseValue);
break;
}
} else {
// C++ [expr.pseudo]p1:
// The result shall only be used as the operand for the function call
// operator (), and the result of such a call has type void. The only
// effect is the evaluation of the postfix-expression before the dot or
// arrow.
EmitScalarExpr(E->getCallee());
}
return RValue::get(0);
}
@ -2016,9 +2164,25 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
return EmitPointerToDataMemberBinaryExpr(E);
assert(E->getOpcode() == BO_Assign && "unexpected binary l-value");
// Note that in all of these cases, __block variables need the RHS
// evaluated first just in case the variable gets moved by the RHS.
if (!hasAggregateLLVMType(E->getType())) {
// __block variables need the RHS evaluated first.
switch (E->getLHS()->getType().getObjCLifetime()) {
case Qualifiers::OCL_Strong:
return EmitARCStoreStrong(E, /*ignored*/ false).first;
case Qualifiers::OCL_Autoreleasing:
return EmitARCStoreAutoreleasing(E).first;
// No reason to do any of these differently.
case Qualifiers::OCL_None:
case Qualifiers::OCL_ExplicitNone:
case Qualifiers::OCL_Weak:
break;
}
RValue RV = EmitAnyExpr(E->getRHS());
LValue LV = EmitLValue(E->getLHS());
EmitStoreThroughLValue(RV, LV, E->getType());

View File

@ -339,6 +339,8 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_IntegralComplexToBoolean:
case CK_IntegralComplexCast:
case CK_IntegralComplexToFloatingComplex:
case CK_ObjCProduceObject:
case CK_ObjCConsumeObject:
llvm_unreachable("cast kind invalid for aggregate types");
}
}
@ -570,8 +572,13 @@ AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV, QualType T) {
} else if (T->isAnyComplexType()) {
CGF.EmitComplexExprIntoAddr(E, LV.getAddress(), false);
} else if (CGF.hasAggregateLLVMType(T)) {
CGF.EmitAggExpr(E, AggValueSlot::forAddr(LV.getAddress(), false, true,
CGF.EmitAggExpr(E, AggValueSlot::forAddr(LV.getAddress(),
T.getQualifiers(), true,
false, Dest.isZeroed()));
} else if (LV.isSimple()) {
CGF.EmitScalarInit(E, /*D=*/0, LV.getAddress(), /*Captured=*/false,
LV.isVolatileQualified(), LV.getAlignment(),
T);
} else {
CGF.EmitStoreThroughLValue(RValue::get(CGF.EmitScalarExpr(E)), LV, T);
}
@ -636,6 +643,8 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
uint64_t NumArrayElements = AType->getNumElements();
QualType ElementType = CGF.getContext().getCanonicalType(E->getType());
ElementType = CGF.getContext().getAsArrayType(ElementType)->getElementType();
ElementType = CGF.getContext().getQualifiedType(ElementType,
Dest.getQualifiers());
bool hasNonTrivialCXXConstructor = false;
if (CGF.getContext().getLangOptions().CPlusPlus)
@ -645,8 +654,6 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
hasNonTrivialCXXConstructor = !RD->hasTrivialDefaultConstructor();
}
// FIXME: were we intentionally ignoring address spaces and GC attributes?
for (uint64_t i = 0; i != NumArrayElements; ++i) {
// If we're done emitting initializers and the destination is known-zeroed
// then we're done.
@ -873,8 +880,6 @@ static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E,
///
/// \param IsInitializer - true if this evaluation is initializing an
/// object whose lifetime is already being managed.
//
// FIXME: Take Qualifiers object.
void CodeGenFunction::EmitAggExpr(const Expr *E, AggValueSlot Slot,
bool IgnoreResult) {
assert(E && hasAggregateLLVMType(E->getType()) &&
@ -892,7 +897,7 @@ LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) {
assert(hasAggregateLLVMType(E->getType()) && "Invalid argument!");
llvm::Value *Temp = CreateMemTemp(E->getType());
LValue LV = MakeAddrLValue(Temp, E->getType());
EmitAggExpr(E, AggValueSlot::forAddr(Temp, LV.isVolatileQualified(), false));
EmitAggExpr(E, AggValueSlot::forLValue(LV, false));
return LV;
}
@ -954,7 +959,10 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
llvm::Type::getInt8PtrTy(getLLVMContext(), SPT->getAddressSpace());
SrcPtr = Builder.CreateBitCast(SrcPtr, SBP, "tmp");
if (const RecordType *RecordTy = Ty->getAs<RecordType>()) {
// Don't do any of the memmove_collectable tests if GC isn't set.
if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC) {
// fall through
} else if (const RecordType *RecordTy = Ty->getAs<RecordType>()) {
RecordDecl *Record = RecordTy->getDecl();
if (Record->hasObjectMember()) {
CharUnits size = TypeInfo.first;
@ -964,7 +972,7 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
SizeVal);
return;
}
} else if (getContext().getAsArrayType(Ty)) {
} else if (Ty->isArrayType()) {
QualType BaseType = getContext().getBaseElementType(Ty);
if (const RecordType *RecordTy = BaseType->getAs<RecordType>()) {
if (RecordTy->getDecl()->hasObjectMember()) {

View File

@ -708,15 +708,14 @@ static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const CXXNewExpr *E,
unsigned Alignment =
CGF.getContext().getTypeAlignInChars(AllocType).getQuantity();
if (!CGF.hasAggregateLLVMType(AllocType))
CGF.EmitStoreOfScalar(CGF.EmitScalarExpr(Init), NewPtr,
AllocType.isVolatileQualified(), Alignment,
AllocType);
CGF.EmitScalarInit(Init, 0, NewPtr, false, AllocType.isVolatileQualified(),
Alignment, AllocType);
else if (AllocType->isAnyComplexType())
CGF.EmitComplexExprIntoAddr(Init, NewPtr,
AllocType.isVolatileQualified());
else {
AggValueSlot Slot
= AggValueSlot::forAddr(NewPtr, AllocType.isVolatileQualified(), true);
= AggValueSlot::forAddr(NewPtr, AllocType.getQualifiers(), true);
CGF.EmitAggExpr(Init, Slot);
}
}
@ -1075,7 +1074,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// CXXNewExpr::shouldNullCheckAllocation()) and we have an
// interesting initializer.
bool nullCheck = allocatorType->isNothrow(getContext()) &&
!(allocType->isPODType() && !E->hasInitializer());
!(allocType.isPODType(getContext()) && !E->hasInitializer());
llvm::BasicBlock *nullCheckBB = 0;
llvm::BasicBlock *contBB = 0;
@ -1247,7 +1246,29 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
if (Dtor)
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
/*ForVirtualBase=*/false, Ptr);
else if (CGF.getLangOptions().ObjCAutoRefCount &&
ElementType->isObjCLifetimeType()) {
switch (ElementType.getObjCLifetime()) {
case Qualifiers::OCL_None:
case Qualifiers::OCL_ExplicitNone:
case Qualifiers::OCL_Autoreleasing:
break;
case Qualifiers::OCL_Strong: {
// Load the pointer value.
llvm::Value *PtrValue = CGF.Builder.CreateLoad(Ptr,
ElementType.isVolatileQualified());
CGF.EmitARCRelease(PtrValue, /*precise*/ true);
break;
}
case Qualifiers::OCL_Weak:
CGF.EmitARCDestroyWeak(Ptr);
break;
}
}
CGF.PopCleanupBlock();
}
@ -1339,6 +1360,65 @@ static void EmitArrayDelete(CodeGenFunction &CGF,
" for a class with destructor");
CGF.EmitCXXAggrDestructorCall(RD->getDestructor(), NumElements, Ptr);
}
} else if (CGF.getLangOptions().ObjCAutoRefCount &&
ElementType->isObjCLifetimeType() &&
(ElementType.getObjCLifetime() == Qualifiers::OCL_Strong ||
ElementType.getObjCLifetime() == Qualifiers::OCL_Weak)) {
bool IsStrong = ElementType.getObjCLifetime() == Qualifiers::OCL_Strong;
const llvm::Type *SizeLTy = CGF.ConvertType(CGF.getContext().getSizeType());
llvm::Value *One = llvm::ConstantInt::get(SizeLTy, 1);
// Create a temporary for the loop index and initialize it with count of
// array elements.
llvm::Value *IndexPtr = CGF.CreateTempAlloca(SizeLTy, "loop.index");
// Store the number of elements in the index pointer.
CGF.Builder.CreateStore(NumElements, IndexPtr);
// Start the loop with a block that tests the condition.
llvm::BasicBlock *CondBlock = CGF.createBasicBlock("for.cond");
llvm::BasicBlock *AfterFor = CGF.createBasicBlock("for.end");
CGF.EmitBlock(CondBlock);
llvm::BasicBlock *ForBody = CGF.createBasicBlock("for.body");
// Generate: if (loop-index != 0 fall to the loop body,
// otherwise, go to the block after the for-loop.
llvm::Value* zeroConstant = llvm::Constant::getNullValue(SizeLTy);
llvm::Value *Counter = CGF.Builder.CreateLoad(IndexPtr);
llvm::Value *IsNE = CGF.Builder.CreateICmpNE(Counter, zeroConstant,
"isne");
// If the condition is true, execute the body.
CGF.Builder.CreateCondBr(IsNE, ForBody, AfterFor);
CGF.EmitBlock(ForBody);
llvm::BasicBlock *ContinueBlock = CGF.createBasicBlock("for.inc");
// Inside the loop body, emit the constructor call on the array element.
Counter = CGF.Builder.CreateLoad(IndexPtr);
Counter = CGF.Builder.CreateSub(Counter, One);
llvm::Value *Address = CGF.Builder.CreateInBoundsGEP(Ptr, Counter,
"arrayidx");
if (IsStrong)
CGF.EmitARCRelease(CGF.Builder.CreateLoad(Address,
ElementType.isVolatileQualified()),
/*precise*/ true);
else
CGF.EmitARCDestroyWeak(Address);
CGF.EmitBlock(ContinueBlock);
// Emit the decrement of the loop counter.
Counter = CGF.Builder.CreateLoad(IndexPtr);
Counter = CGF.Builder.CreateSub(Counter, One, "dec");
CGF.Builder.CreateStore(Counter, IndexPtr);
// Finally, branch back up to the condition for the next iteration.
CGF.EmitBranch(CondBlock);
// Emit the fall-through block.
CGF.EmitBlock(AfterFor, true);
}
CGF.PopCleanupBlock();

View File

@ -570,6 +570,8 @@ public:
case CK_GetObjCProperty:
case CK_ToVoid:
case CK_Dynamic:
case CK_ObjCProduceObject:
case CK_ObjCConsumeObject:
return 0;
// These might need to be supported for constexpr.

View File

@ -1106,7 +1106,12 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
// function pointers on Itanium and ARM).
return CGF.CGM.getCXXABI().EmitMemberPointerConversion(CGF, CE, Src);
}
case CK_ObjCProduceObject:
return CGF.EmitARCRetainScalarExpr(E);
case CK_ObjCConsumeObject:
return CGF.EmitObjCConsumeObject(E->getType(), Visit(E));
case CK_FloatingRealToComplex:
case CK_FloatingComplexCast:
case CK_IntegralRealToComplex:
@ -2228,20 +2233,42 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
bool Ignore = TestAndClearIgnoreResultAssign();
// __block variables need to have the rhs evaluated first, plus this should
// improve codegen just a little.
Value *RHS = Visit(E->getRHS());
LValue LHS = EmitCheckedLValue(E->getLHS());
Value *RHS;
LValue LHS;
// Store the value into the LHS. Bit-fields are handled specially
// because the result is altered by the store, i.e., [C99 6.5.16p1]
// 'An assignment expression has the value of the left operand after
// the assignment...'.
if (LHS.isBitField())
CGF.EmitStoreThroughBitfieldLValue(RValue::get(RHS), LHS, E->getType(),
&RHS);
else
CGF.EmitStoreThroughLValue(RValue::get(RHS), LHS, E->getType());
switch (E->getLHS()->getType().getObjCLifetime()) {
case Qualifiers::OCL_Strong:
llvm::tie(LHS, RHS) = CGF.EmitARCStoreStrong(E, Ignore);
break;
case Qualifiers::OCL_Autoreleasing:
llvm::tie(LHS,RHS) = CGF.EmitARCStoreAutoreleasing(E);
break;
case Qualifiers::OCL_Weak:
RHS = Visit(E->getRHS());
LHS = EmitCheckedLValue(E->getLHS());
RHS = CGF.EmitARCStoreWeak(LHS.getAddress(), RHS, Ignore);
break;
// No reason to do any of these differently.
case Qualifiers::OCL_None:
case Qualifiers::OCL_ExplicitNone:
// __block variables need to have the rhs evaluated first, plus
// this should improve codegen just a little.
RHS = Visit(E->getRHS());
LHS = EmitCheckedLValue(E->getLHS());
// Store the value into the LHS. Bit-fields are handled specially
// because the result is altered by the store, i.e., [C99 6.5.16p1]
// 'An assignment expression has the value of the left operand after
// the assignment...'.
if (LHS.isBitField())
CGF.EmitStoreThroughBitfieldLValue(RValue::get(RHS), LHS, E->getType(),
&RHS);
else
CGF.EmitStoreThroughLValue(RValue::get(RHS), LHS, E->getType());
}
// If the result is clearly ignored, return now.
if (Ignore)

File diff suppressed because it is too large Load Diff

View File

@ -969,7 +969,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
ActualArgs.add(RValue::get(EnforceType(Builder, Receiver, IdTy)), ASTIdTy);
ActualArgs.add(RValue::get(cmd), CGF.getContext().getObjCSelType());
ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
ActualArgs.addFrom(CallArgs);
CodeGenTypes &Types = CGM.getTypes();
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
@ -1121,7 +1121,7 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
CallArgList ActualArgs;
ActualArgs.add(RValue::get(Receiver), ASTIdTy);
ActualArgs.add(RValue::get(cmd), CGF.getContext().getObjCSelType());
ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
ActualArgs.addFrom(CallArgs);
CodeGenTypes &Types = CGM.getTypes();
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,

View File

@ -63,10 +63,13 @@ private:
/// The default messenger, used for sends whose ABI is unchanged from
/// the all-integer/pointer case.
llvm::Constant *getMessageSendFn() const {
// Add the non-lazy-bind attribute, since objc_msgSend is likely to
// be called a lot.
const llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSend");
"objc_msgSend",
llvm::Attribute::NonLazyBind);
}
/// void objc_msgSend_stret (id, SEL, ...)
@ -887,6 +890,11 @@ private:
llvm::Value *EmitClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID);
llvm::Value *EmitClassRefFromId(CGBuilderTy &Builder,
IdentifierInfo *II);
llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder);
/// EmitSuperClassRef - Emits reference to class's main metadata class.
llvm::Value *EmitSuperClassRef(const ObjCInterfaceDecl *ID);
@ -1158,6 +1166,11 @@ private:
/// for the given class reference.
llvm::Value *EmitClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID);
llvm::Value *EmitClassRefFromId(CGBuilderTy &Builder,
IdentifierInfo *II);
llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder);
/// EmitSuperClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
/// for the given super class reference.
@ -1526,7 +1539,7 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy, "tmp");
ActualArgs.add(RValue::get(Arg0), Arg0Ty);
ActualArgs.add(RValue::get(Sel), CGF.getContext().getObjCSelType());
ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
ActualArgs.addFrom(CallArgs);
CodeGenTypes &Types = CGM.getTypes();
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
@ -1562,7 +1575,7 @@ static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) {
if (FQT.isObjCGCStrong())
return Qualifiers::Strong;
if (FQT.isObjCGCWeak())
if (FQT.isObjCGCWeak() || FQT.getObjCLifetime() == Qualifiers::OCL_Weak)
return Qualifiers::Weak;
if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType())
@ -1579,7 +1592,8 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
llvm::Constant *nullPtr =
llvm::Constant::getNullValue(llvm::Type::getInt8PtrTy(VMContext));
if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC)
if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC &&
!CGM.getLangOptions().ObjCAutoRefCount)
return nullPtr;
bool hasUnion = false;
@ -2129,7 +2143,7 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
Interface->all_referenced_protocol_begin(),
Interface->all_referenced_protocol_end());
unsigned Flags = eClassFlags_Factory;
if (ID->getNumIvarInitializers())
if (ID->hasCXXStructors())
Flags |= eClassFlags_HasCXXStructors;
unsigned Size =
CGM.getContext().getASTObjCImplementationLayout(ID).getSize().getQuantity();
@ -3461,25 +3475,35 @@ llvm::Constant *CGObjCMac::EmitModuleSymbols() {
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.SymtabPtrTy);
}
llvm::Value *CGObjCMac::EmitClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID) {
LazySymbols.insert(ID->getIdentifier());
llvm::GlobalVariable *&Entry = ClassReferences[ID->getIdentifier()];
llvm::Value *CGObjCMac::EmitClassRefFromId(CGBuilderTy &Builder,
IdentifierInfo *II) {
LazySymbols.insert(II);
llvm::GlobalVariable *&Entry = ClassReferences[II];
if (!Entry) {
llvm::Constant *Casted =
llvm::ConstantExpr::getBitCast(GetClassName(ID->getIdentifier()),
ObjCTypes.ClassPtrTy);
llvm::ConstantExpr::getBitCast(GetClassName(II),
ObjCTypes.ClassPtrTy);
Entry =
CreateMetadataVar("\01L_OBJC_CLASS_REFERENCES_", Casted,
"__OBJC,__cls_refs,literal_pointers,no_dead_strip",
4, true);
CreateMetadataVar("\01L_OBJC_CLASS_REFERENCES_", Casted,
"__OBJC,__cls_refs,literal_pointers,no_dead_strip",
4, true);
}
return Builder.CreateLoad(Entry, "tmp");
}
llvm::Value *CGObjCMac::EmitClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID) {
return EmitClassRefFromId(Builder, ID->getIdentifier());
}
llvm::Value *CGObjCMac::EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder) {
IdentifierInfo *II = &CGM.getContext().Idents.get("NSAutoreleasePool");
return EmitClassRefFromId(Builder, II);
}
llvm::Value *CGObjCMac::EmitSelector(CGBuilderTy &Builder, Selector Sel,
bool lvalue) {
llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
@ -3567,12 +3591,18 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
uint64_t MaxFieldOffset = 0;
uint64_t MaxSkippedFieldOffset = 0;
uint64_t LastBitfieldOrUnnamedOffset = 0;
uint64_t FirstFieldDelta = 0;
if (RecFields.empty())
return;
unsigned WordSizeInBits = CGM.getContext().Target.getPointerWidth(0);
unsigned ByteSizeInBits = CGM.getContext().Target.getCharWidth();
if (!RD && CGM.getLangOptions().ObjCAutoRefCount) {
FieldDecl *FirstField = RecFields[0];
FirstFieldDelta =
ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(FirstField));
}
for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
FieldDecl *Field = RecFields[i];
uint64_t FieldOffset;
@ -3580,9 +3610,10 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
// Note that 'i' here is actually the field index inside RD of Field,
// although this dependency is hidden.
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
FieldOffset = RL.getFieldOffset(i) / ByteSizeInBits;
FieldOffset = (RL.getFieldOffset(i) / ByteSizeInBits) - FirstFieldDelta;
} else
FieldOffset = ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(Field));
FieldOffset =
ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(Field)) - FirstFieldDelta;
// Skip over unnamed or bitfields
if (!Field->getIdentifier() || Field->isBitField()) {
@ -3861,12 +3892,16 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
bool hasUnion = false;
const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext);
if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC)
if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC &&
!CGM.getLangOptions().ObjCAutoRefCount)
return llvm::Constant::getNullValue(PtrTy);
llvm::SmallVector<ObjCIvarDecl*, 32> Ivars;
const ObjCInterfaceDecl *OI = OMD->getClassInterface();
CGM.getContext().DeepCollectObjCIvars(OI, true, Ivars);
if (CGM.getLangOptions().ObjCAutoRefCount)
CGM.getContext().ShallowCollectObjCIvars(OI, Ivars);
else
CGM.getContext().DeepCollectObjCIvars(OI, true, Ivars);
llvm::SmallVector<FieldDecl*, 32> RecFields;
for (unsigned k = 0, e = Ivars.size(); k != e; ++k)
@ -4743,7 +4778,12 @@ enum MetaDataDlags {
CLS_META = 0x1,
CLS_ROOT = 0x2,
OBJC2_CLS_HIDDEN = 0x10,
CLS_EXCEPTION = 0x20
CLS_EXCEPTION = 0x20,
/// (Obsolete) ARC-specific: this class has a .release_ivars method
CLS_HAS_IVAR_RELEASER = 0x40,
/// class was compiled with -fobjc-arr
CLS_COMPILED_BY_ARC = 0x80 // (1<<7)
};
/// BuildClassRoTInitializer - generate meta-data for:
/// struct _class_ro_t {
@ -4767,6 +4807,10 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
const ObjCImplementationDecl *ID) {
std::string ClassName = ID->getNameAsString();
std::vector<llvm::Constant*> Values(10); // 11 for 64bit targets!
if (CGM.getLangOptions().ObjCAutoRefCount)
flags |= CLS_COMPILED_BY_ARC;
Values[ 0] = llvm::ConstantInt::get(ObjCTypes.IntTy, flags);
Values[ 1] = llvm::ConstantInt::get(ObjCTypes.IntTy, InstanceStart);
Values[ 2] = llvm::ConstantInt::get(ObjCTypes.IntTy, InstanceSize);
@ -4936,7 +4980,7 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
ID->getClassInterface()->getVisibility() == HiddenVisibility;
if (classIsHidden)
flags |= OBJC2_CLS_HIDDEN;
if (ID->getNumIvarInitializers())
if (ID->hasCXXStructors())
flags |= eClassFlags_ABI2_HasCXXStructors;
if (!ID->getClassInterface()->getSuperClass()) {
// class is root
@ -4972,7 +5016,7 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
flags = CLS;
if (classIsHidden)
flags |= OBJC2_CLS_HIDDEN;
if (ID->getNumIvarInitializers())
if (ID->hasCXXStructors())
flags |= eClassFlags_ABI2_HasCXXStructors;
if (hasObjCExceptionAttribute(CGM.getContext(), ID->getClassInterface()))
@ -5719,28 +5763,39 @@ CGObjCNonFragileABIMac::GetClassGlobal(const std::string &Name) {
return GV;
}
llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID) {
llvm::GlobalVariable *&Entry = ClassReferences[ID->getIdentifier()];
llvm::Value *CGObjCNonFragileABIMac::EmitClassRefFromId(CGBuilderTy &Builder,
IdentifierInfo *II) {
llvm::GlobalVariable *&Entry = ClassReferences[II];
if (!Entry) {
std::string ClassName(getClassSymbolPrefix() + ID->getNameAsString());
std::string ClassName(getClassSymbolPrefix() + II->getName().str());
llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName);
Entry =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
false, llvm::GlobalValue::InternalLinkage,
ClassGV,
"\01L_OBJC_CLASSLIST_REFERENCES_$_");
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
false, llvm::GlobalValue::InternalLinkage,
ClassGV,
"\01L_OBJC_CLASSLIST_REFERENCES_$_");
Entry->setAlignment(
CGM.getTargetData().getABITypeAlignment(
ObjCTypes.ClassnfABIPtrTy));
CGM.getTargetData().getABITypeAlignment(
ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_classrefs, regular, no_dead_strip");
CGM.AddUsedGlobal(Entry);
}
return Builder.CreateLoad(Entry, "tmp");
}
llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID) {
return EmitClassRefFromId(Builder, ID->getIdentifier());
}
llvm::Value *CGObjCNonFragileABIMac::EmitNSAutoreleasePoolClassRef(
CGBuilderTy &Builder) {
IdentifierInfo *II = &CGM.getContext().Idents.get("NSAutoreleasePool");
return EmitClassRefFromId(Builder, II);
}
llvm::Value *
CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID) {

View File

@ -205,7 +205,13 @@ public:
/// interface decl.
virtual llvm::Value *GetClass(CGBuilderTy &Builder,
const ObjCInterfaceDecl *OID) = 0;
virtual llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder) {
assert(false &&"autoreleasepool unsupported in this ABI");
return 0;
}
/// EnumerationMutationFunction - Return the function that's called by the
/// compiler when a mutation is detected during foreach iteration.
virtual llvm::Constant *EnumerationMutationFunction() = 0;

View File

@ -151,6 +151,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
case Stmt::ObjCForCollectionStmtClass:
EmitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(*S));
break;
case Stmt::ObjCAutoreleasePoolStmtClass:
EmitObjCAutoreleasePoolStmt(cast<ObjCAutoreleasePoolStmt>(*S));
break;
case Stmt::CXXTryStmtClass:
EmitCXXTryStmt(cast<CXXTryStmt>(*S));
@ -764,7 +767,7 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
} else if (RV->getType()->isAnyComplexType()) {
EmitComplexExprIntoAddr(RV, ReturnValue, false);
} else {
EmitAggExpr(RV, AggValueSlot::forAddr(ReturnValue, false, true));
EmitAggExpr(RV, AggValueSlot::forAddr(ReturnValue, Qualifiers(), true));
}
EmitBranchThroughCleanup(ReturnBlock);

View File

@ -101,8 +101,6 @@ public:
/// bitfields, this is not a simple LLVM pointer, it may be a pointer plus a
/// bitrange.
class LValue {
// FIXME: alignment?
enum {
Simple, // This is a normal l-value, use getAddress().
VectorElt, // This is a vector element l-value (V[i]), use getVector*
@ -318,9 +316,11 @@ public:
class AggValueSlot {
/// The address.
llvm::Value *Addr;
// Qualifiers
Qualifiers Quals;
// Associated flags.
bool VolatileFlag : 1;
bool LifetimeFlag : 1;
bool RequiresGCollection : 1;
@ -335,25 +335,31 @@ public:
static AggValueSlot ignored() {
AggValueSlot AV;
AV.Addr = 0;
AV.VolatileFlag = AV.LifetimeFlag = AV.RequiresGCollection = AV.IsZeroed =0;
AV.Quals = Qualifiers();
AV.LifetimeFlag = AV.RequiresGCollection = AV.IsZeroed =0;
return AV;
}
/// forAddr - Make a slot for an aggregate value.
///
/// \param Volatile - true if the slot should be volatile-initialized
///
/// \param Qualifiers - The qualifiers that dictate how the slot
/// should be initialied. Only 'volatile' and the Objective-C
/// lifetime qualifiers matter.
///
/// \param LifetimeExternallyManaged - true if the slot's lifetime
/// is being externally managed; false if a destructor should be
/// registered for any temporaries evaluated into the slot
/// \param RequiresGCollection - true if the slot is located
/// somewhere that ObjC GC calls should be emitted for
static AggValueSlot forAddr(llvm::Value *Addr, bool Volatile,
static AggValueSlot forAddr(llvm::Value *Addr, Qualifiers Quals,
bool LifetimeExternallyManaged,
bool RequiresGCollection = false,
bool IsZeroed = false) {
AggValueSlot AV;
AV.Addr = Addr;
AV.VolatileFlag = Volatile;
AV.Quals = Quals;
AV.LifetimeFlag = LifetimeExternallyManaged;
AV.RequiresGCollection = RequiresGCollection;
AV.IsZeroed = IsZeroed;
@ -362,7 +368,7 @@ public:
static AggValueSlot forLValue(LValue LV, bool LifetimeExternallyManaged,
bool RequiresGCollection = false) {
return forAddr(LV.getAddress(), LV.isVolatileQualified(),
return forAddr(LV.getAddress(), LV.getQuals(),
LifetimeExternallyManaged, RequiresGCollection);
}
@ -373,8 +379,14 @@ public:
LifetimeFlag = Managed;
}
Qualifiers getQualifiers() const { return Quals; }
bool isVolatile() const {
return VolatileFlag;
return Quals.hasVolatile();
}
Qualifiers::ObjCLifetime getObjCLifetime() const {
return Quals.getObjCLifetime();
}
bool requiresGCollection() const {

View File

@ -31,7 +31,7 @@ using namespace CodeGen;
CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
: CodeGenTypeCache(cgm), CGM(cgm),
Target(CGM.getContext().Target), Builder(cgm.getModule().getContext()),
BlockInfo(0), BlockPointer(0),
AutoreleaseResult(false), BlockInfo(0), BlockPointer(0),
NormalCleanupDest(0), EHCleanupDest(0), NextCleanupDestIndex(1),
ExceptionSlot(0), EHSelectorSlot(0),
DebugInfo(0), DisableDebugInfo(false), DidCallStackSave(false),
@ -142,6 +142,13 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
assert(BreakContinueStack.empty() &&
"mismatched push/pop in break/continue stack!");
// Pop any cleanups that might have been associated with the
// parameters. Do this in whatever block we're currently in; it's
// important to do this before we enter the return block or return
// edges will be *really* confused.
if (EHStack.stable_begin() != PrologueCleanupDepth)
PopCleanupBlocks(PrologueCleanupDepth);
// Emit function epilog (to return).
EmitReturnBlock();
@ -311,9 +318,19 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
ReturnValue = CurFn->arg_begin();
} else {
ReturnValue = CreateIRTemp(RetTy, "retval");
// Tell the epilog emitter to autorelease the result. We do this
// now so that various specialized functions can suppress it
// during their IR-generation.
if (getLangOptions().ObjCAutoRefCount &&
!CurFnInfo->isReturnsRetained() &&
RetTy->isObjCRetainableType())
AutoreleaseResult = true;
}
EmitStartEHSpec(CurCodeDecl);
PrologueCleanupDepth = EHStack.stable_begin();
EmitFunctionProlog(*CurFnInfo, CurFn, Args);
if (D && isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance())

View File

@ -18,6 +18,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/CharUnits.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/DenseMap.h"
@ -63,6 +64,7 @@ namespace clang {
class ObjCAtTryStmt;
class ObjCAtThrowStmt;
class ObjCAtSynchronizedStmt;
class ObjCAutoreleasePoolStmt;
namespace CodeGen {
class CodeGenTypes;
@ -568,6 +570,10 @@ public:
/// CurGD - The GlobalDecl for the current function being compiled.
GlobalDecl CurGD;
/// PrologueCleanupDepth - The cleanup depth enclosing all the
/// cleanups associated with the parameters.
EHScopeStack::stable_iterator PrologueCleanupDepth;
/// ReturnBlock - Unified return block.
JumpDest ReturnBlock;
@ -584,6 +590,9 @@ public:
bool CatchUndefined;
/// In ARC, whether we should autorelease the return value.
bool AutoreleaseResult;
const CodeGen::CGBlockInfo *BlockInfo;
llvm::Value *BlockPointer;
@ -1048,6 +1057,9 @@ public:
void disableDebugInfo() { DisableDebugInfo = true; }
void enableDebugInfo() { DisableDebugInfo = false; }
bool shouldUseFusedARCCalls() {
return CGM.getCodeGenOpts().OptimizationLevel == 0;
}
const LangOptions &getLangOptions() const { return CGM.getLangOptions(); }
@ -1345,7 +1357,8 @@ public:
/// CreateAggTemp - Create a temporary memory object for the given
/// aggregate type.
AggValueSlot CreateAggTemp(QualType T, const llvm::Twine &Name = "tmp") {
return AggValueSlot::forAddr(CreateMemTemp(T, Name), false, false);
return AggValueSlot::forAddr(CreateMemTemp(T, Name), T.getQualifiers(),
false);
}
/// Emit a cast to void* in the appropriate address space.
@ -1379,12 +1392,11 @@ public:
/// EmitAnyExprToMem - Emits the code necessary to evaluate an
/// arbitrary expression into the given memory location.
void EmitAnyExprToMem(const Expr *E, llvm::Value *Location,
bool IsLocationVolatile,
bool IsInitializer);
Qualifiers Quals, bool IsInitializer);
/// EmitExprAsInit - Emits the code necessary to initialize a
/// location in memory with the given initializer.
void EmitExprAsInit(const Expr *init, const VarDecl *var,
void EmitExprAsInit(const Expr *init, const ValueDecl *D,
llvm::Value *loc, CharUnits alignment,
bool capturedByInit);
@ -1584,6 +1596,10 @@ public:
/// This function can be called with a null (unreachable) insert point.
void EmitVarDecl(const VarDecl &D);
void EmitScalarInit(const Expr *init, const ValueDecl *D,
llvm::Value *addr, bool capturedByInit,
bool isVolatile, unsigned alignment, QualType type);
typedef void SpecialInitFn(CodeGenFunction &Init, const VarDecl &D,
llvm::Value *Address);
@ -1709,6 +1725,7 @@ public:
void EmitObjCAtTryStmt(const ObjCAtTryStmt &S);
void EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S);
void EmitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt &S);
void EmitObjCAutoreleasePoolStmt(const ObjCAutoreleasePoolStmt &S);
llvm::Constant *getUnwindResumeFn();
llvm::Constant *getUnwindResumeOrRethrowFn();
@ -1961,6 +1978,64 @@ public:
RValue EmitObjCMessageExpr(const ObjCMessageExpr *E,
ReturnValueSlot Return = ReturnValueSlot());
/// Retrieves the default cleanup kind for an ARC cleanup.
/// Except under -fobjc-arc-eh, ARC cleanups are normal-only.
CleanupKind getARCCleanupKind() {
return CGM.getCodeGenOpts().ObjCAutoRefCountExceptions
? NormalAndEHCleanup : NormalCleanup;
}
// ARC primitives.
void EmitARCInitWeak(llvm::Value *value, llvm::Value *addr);
void EmitARCDestroyWeak(llvm::Value *addr);
llvm::Value *EmitARCLoadWeak(llvm::Value *addr);
llvm::Value *EmitARCLoadWeakRetained(llvm::Value *addr);
llvm::Value *EmitARCStoreWeak(llvm::Value *value, llvm::Value *addr,
bool ignored);
void EmitARCCopyWeak(llvm::Value *dst, llvm::Value *src);
void EmitARCMoveWeak(llvm::Value *dst, llvm::Value *src);
llvm::Value *EmitARCRetainAutorelease(QualType type, llvm::Value *value);
llvm::Value *EmitARCRetainAutoreleaseNonBlock(llvm::Value *value);
llvm::Value *EmitARCStoreStrong(LValue addr, QualType type,
llvm::Value *value, bool ignored);
llvm::Value *EmitARCStoreStrongCall(llvm::Value *addr, llvm::Value *value,
bool ignored);
llvm::Value *EmitARCRetain(QualType type, llvm::Value *value);
llvm::Value *EmitARCRetainNonBlock(llvm::Value *value);
llvm::Value *EmitARCRetainBlock(llvm::Value *value);
void EmitARCRelease(llvm::Value *value, bool precise);
llvm::Value *EmitARCAutorelease(llvm::Value *value);
llvm::Value *EmitARCAutoreleaseReturnValue(llvm::Value *value);
llvm::Value *EmitARCRetainAutoreleaseReturnValue(llvm::Value *value);
llvm::Value *EmitARCRetainAutoreleasedReturnValue(llvm::Value *value);
std::pair<LValue,llvm::Value*>
EmitARCStoreAutoreleasing(const BinaryOperator *e);
std::pair<LValue,llvm::Value*>
EmitARCStoreStrong(const BinaryOperator *e, bool ignored);
llvm::Value *EmitObjCProduceObject(QualType T, llvm::Value *Ptr);
llvm::Value *EmitObjCConsumeObject(QualType T, llvm::Value *Ptr);
llvm::Value *EmitObjCExtendObjectLifetime(QualType T, llvm::Value *Ptr);
llvm::Value *EmitARCRetainScalarExpr(const Expr *expr);
llvm::Value *EmitARCRetainAutoreleaseScalarExpr(const Expr *expr);
void PushARCReleaseCleanup(CleanupKind kind, QualType type,
llvm::Value *addr, bool precise);
void PushARCWeakReleaseCleanup(CleanupKind kind, QualType type,
llvm::Value *addr);
void PushARCFieldReleaseCleanup(CleanupKind cleanupKind,
const FieldDecl *Field);
void PushARCFieldWeakReleaseCleanup(CleanupKind cleanupKind,
const FieldDecl *Field);
void EmitObjCAutoreleasePoolPop(llvm::Value *Ptr);
llvm::Value *EmitObjCAutoreleasePoolPush();
llvm::Value *EmitObjCMRRAutoreleasePoolPush();
void EmitObjCAutoreleasePoolCleanup(llvm::Value *Ptr);
void EmitObjCMRRAutoreleasePoolPop(llvm::Value *Ptr);
/// EmitReferenceBindingToExpr - Emits a reference binding to the passed in
/// expression. Will emit a temporary variable if E is not an LValue.
RValue EmitReferenceBindingToExpr(const Expr* E,

View File

@ -64,7 +64,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
ABI(createCXXABI(*this)),
Types(C, M, TD, getTargetCodeGenInfo().getABIInfo(), ABI),
TBAA(0),
VTables(*this), Runtime(0), DebugInfo(0),
VTables(*this), Runtime(0), DebugInfo(0), ARCData(0), RRData(0),
CFConstantStringClassRef(0), ConstantStringClassRef(0),
VMContext(M.getContext()),
NSConcreteGlobalBlockDecl(0), NSConcreteStackBlockDecl(0),
@ -88,6 +88,10 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
Block.GlobalUniqueCount = 0;
if (C.getLangOptions().ObjCAutoRefCount)
ARCData = new ARCEntrypoints();
RRData = new RREntrypoints();
// Initialize the type cache.
llvm::LLVMContext &LLVMContext = M.getContext();
VoidTy = llvm::Type::getVoidTy(LLVMContext);
@ -108,6 +112,8 @@ CodeGenModule::~CodeGenModule() {
delete &ABI;
delete TBAA;
delete DebugInfo;
delete ARCData;
delete RRData;
}
void CodeGenModule::createObjCRuntime() {
@ -830,7 +836,8 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
llvm::Constant *
CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName,
const llvm::Type *Ty,
GlobalDecl D, bool ForVTable) {
GlobalDecl D, bool ForVTable,
llvm::Attributes ExtraAttrs) {
// Lookup the entry, lazily creating it if necessary.
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry) {
@ -869,6 +876,8 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName,
assert(F->getName() == MangledName && "name was uniqued!");
if (D.getDecl())
SetFunctionAttributes(D, F, IsIncompleteFunction);
if (ExtraAttrs != llvm::Attribute::None)
F->addFnAttr(ExtraAttrs);
// This is the first use or definition of a mangled name. If there is a
// deferred decl with this name, remember that we need to emit it at the end
@ -937,8 +946,10 @@ llvm::Constant *CodeGenModule::GetAddrOfFunction(GlobalDecl GD,
/// type and name.
llvm::Constant *
CodeGenModule::CreateRuntimeFunction(const llvm::FunctionType *FTy,
llvm::StringRef Name) {
return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false);
llvm::StringRef Name,
llvm::Attributes ExtraAttrs) {
return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false,
ExtraAttrs);
}
static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D,
@ -1997,6 +2008,7 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
false, true, false, ObjCMethodDecl::Required);
D->addInstanceMethod(DTORMethod);
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false);
D->setHasCXXStructors(true);
}
// If the implementation doesn't have any ivar initializers, we don't need
@ -2015,6 +2027,7 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
ObjCMethodDecl::Required);
D->addInstanceMethod(CTORMethod);
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true);
D->setHasCXXStructors(true);
}
/// EmitNamespace - Emit all declarations in a namespace.

View File

@ -131,6 +131,71 @@ namespace CodeGen {
/// The alignment of a pointer into the generic address space.
unsigned char PointerAlignInBytes;
};
struct RREntrypoints {
RREntrypoints() { memset(this, 0, sizeof(*this)); }
/// void objc_autoreleasePoolPop(void*);
llvm::Constant *objc_autoreleasePoolPop;
/// void *objc_autoreleasePoolPush(void);
llvm::Constant *objc_autoreleasePoolPush;
};
struct ARCEntrypoints {
ARCEntrypoints() { memset(this, 0, sizeof(*this)); }
/// id objc_autorelease(id);
llvm::Constant *objc_autorelease;
/// id objc_autoreleaseReturnValue(id);
llvm::Constant *objc_autoreleaseReturnValue;
/// void objc_copyWeak(id *dest, id *src);
llvm::Constant *objc_copyWeak;
/// void objc_destroyWeak(id*);
llvm::Constant *objc_destroyWeak;
/// id objc_initWeak(id*, id);
llvm::Constant *objc_initWeak;
/// id objc_loadWeak(id*);
llvm::Constant *objc_loadWeak;
/// id objc_loadWeakRetained(id*);
llvm::Constant *objc_loadWeakRetained;
/// void objc_moveWeak(id *dest, id *src);
llvm::Constant *objc_moveWeak;
/// id objc_retain(id);
llvm::Constant *objc_retain;
/// id objc_retainAutorelease(id);
llvm::Constant *objc_retainAutorelease;
/// id objc_retainAutoreleaseReturnValue(id);
llvm::Constant *objc_retainAutoreleaseReturnValue;
/// id objc_retainAutoreleasedReturnValue(id);
llvm::Constant *objc_retainAutoreleasedReturnValue;
/// id objc_retainBlock(id);
llvm::Constant *objc_retainBlock;
/// void objc_release(id);
llvm::Constant *objc_release;
/// id objc_storeStrong(id*, id);
llvm::Constant *objc_storeStrong;
/// id objc_storeWeak(id*, id);
llvm::Constant *objc_storeWeak;
/// A void(void) inline asm to use to mark that the return value of
/// a call will be immediately retain.
llvm::InlineAsm *retainAutoreleasedReturnValueMarker;
};
/// CodeGenModule - This class organizes the cross-function state that is used
/// while generating LLVM code.
@ -157,6 +222,8 @@ class CodeGenModule : public CodeGenTypeCache {
CGObjCRuntime* Runtime;
CGDebugInfo* DebugInfo;
ARCEntrypoints *ARCData;
RREntrypoints *RRData;
// WeakRefReferences - A set of references that have only been seen via
// a weakref so far. This is used to remove the weak of the reference if we ever
@ -275,6 +342,16 @@ public:
/// getCXXABI() - Return a reference to the configured C++ ABI.
CGCXXABI &getCXXABI() { return ABI; }
ARCEntrypoints &getARCEntrypoints() const {
assert(getLangOptions().ObjCAutoRefCount && ARCData != 0);
return *ARCData;
}
RREntrypoints &getRREntrypoints() const {
assert(RRData != 0);
return *RRData;
}
llvm::Value *getStaticLocalDeclAddress(const VarDecl *VD) {
return StaticLocalDeclMap[VD];
}
@ -474,7 +551,7 @@ public:
/// created).
llvm::Constant *GetAddrOfConstantCString(const std::string &str,
const char *GlobalName=0);
/// GetAddrOfCXXConstructor - Return the address of the constructor of the
/// given type.
llvm::GlobalValue *GetAddrOfCXXConstructor(const CXXConstructorDecl *ctor,
@ -514,7 +591,9 @@ public:
/// CreateRuntimeFunction - Create a new runtime function with the specified
/// type and name.
llvm::Constant *CreateRuntimeFunction(const llvm::FunctionType *Ty,
llvm::StringRef Name);
llvm::StringRef Name,
llvm::Attributes ExtraAttrs =
llvm::Attribute::None);
/// CreateRuntimeVariable - Create a new runtime global variable with the
/// specified type and name.
llvm::Constant *CreateRuntimeVariable(const llvm::Type *Ty,
@ -642,7 +721,9 @@ private:
llvm::Constant *GetOrCreateLLVMFunction(llvm::StringRef MangledName,
const llvm::Type *Ty,
GlobalDecl D,
bool ForVTable);
bool ForVTable,
llvm::Attributes ExtraAttrs =
llvm::Attribute::None);
llvm::Constant *GetOrCreateLLVMGlobal(llvm::StringRef MangledName,
const llvm::PointerType *PTy,
const VarDecl *D,

View File

@ -802,10 +802,27 @@ bool ItaniumCXXABI::NeedsArrayCookie(const CXXNewExpr *expr) {
if (expr->doesUsualArrayDeleteWantSize())
return true;
// Automatic Reference Counting:
// We need an array cookie for pointers with strong or weak lifetime.
QualType AllocatedType = expr->getAllocatedType();
if (getContext().getLangOptions().ObjCAutoRefCount &&
AllocatedType->isObjCLifetimeType()) {
switch (AllocatedType.getObjCLifetime()) {
case Qualifiers::OCL_None:
case Qualifiers::OCL_ExplicitNone:
case Qualifiers::OCL_Autoreleasing:
return false;
case Qualifiers::OCL_Strong:
case Qualifiers::OCL_Weak:
return true;
}
}
// Otherwise, if the class has a non-trivial destructor, it always
// needs a cookie.
const CXXRecordDecl *record =
expr->getAllocatedType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
AllocatedType->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
return (record && !record->hasTrivialDestructor());
}
@ -816,6 +833,22 @@ bool ItaniumCXXABI::NeedsArrayCookie(const CXXDeleteExpr *expr,
if (expr->doesUsualArrayDeleteWantSize())
return true;
// Automatic Reference Counting:
// We need an array cookie for pointers with strong or weak lifetime.
if (getContext().getLangOptions().ObjCAutoRefCount &&
elementType->isObjCLifetimeType()) {
switch (elementType.getObjCLifetime()) {
case Qualifiers::OCL_None:
case Qualifiers::OCL_ExplicitNone:
case Qualifiers::OCL_Autoreleasing:
return false;
case Qualifiers::OCL_Strong:
case Qualifiers::OCL_Weak:
return true;
}
}
// Otherwise, if the class has a non-trivial destructor, it always
// needs a cookie.
const CXXRecordDecl *record =

View File

@ -2277,6 +2277,10 @@ public:
return 13;
}
llvm::StringRef getARCRetainAutoreleasedReturnValueMarker() const {
return "mov\tr7, r7\t\t@ marker for objc_retainAutoreleaseReturnValue";
}
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
llvm::Value *Address) const {
CodeGen::CGBuilderTy &Builder = CGF.Builder;
@ -2290,8 +2294,6 @@ public:
return false;
}
};
}

View File

@ -111,6 +111,20 @@ namespace clang {
const llvm::Type* Ty) const {
return Ty;
}
/// Retrieve the address of a function to call immediately before
/// calling objc_retainAutoreleasedReturnValue. The
/// implementation of objc_autoreleaseReturnValue sniffs the
/// instruction stream following its return address to decide
/// whether it's a call to objc_retainAutoreleasedReturnValue.
/// This can be prohibitively expensive, depending on the
/// relocation model, and so on some targets it instead sniffs for
/// a particular instruction sequence. This functions returns
/// that instruction sequence in inline assembly, which will be
/// empty if none is required.
virtual llvm::StringRef getARCRetainAutoreleasedReturnValueMarker() const {
return "";
}
};
}

View File

@ -201,7 +201,8 @@ ToolChain::CXXStdlibType ToolChain::GetCXXStdlibType(const ArgList &Args) const{
}
void ToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
ArgStringList &CmdArgs,
bool ObjCXXAutoRefCount) const {
CXXStdlibType Type = GetCXXStdlibType(Args);
switch (Type) {
@ -209,10 +210,16 @@ void ToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args,
CmdArgs.push_back("-nostdinc++");
CmdArgs.push_back("-cxx-isystem");
CmdArgs.push_back("/usr/include/c++/v1");
if (ObjCXXAutoRefCount)
CmdArgs.push_back("-fobjc-arc-cxxlib=libc++");
break;
case ToolChain::CST_Libstdcxx:
// Currently handled by the mass of goop in InitHeaderSearch.
if (ObjCXXAutoRefCount)
CmdArgs.push_back("-fobjc-arc-cxxlib=libstdc++");
break;
}
}

View File

@ -26,6 +26,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
@ -41,7 +42,8 @@ using namespace clang::driver::toolchains;
/// Darwin - Darwin tool chain for i386 and x86_64.
Darwin::Darwin(const HostInfo &Host, const llvm::Triple& Triple)
: ToolChain(Host, Triple), TargetInitialized(false)
: ToolChain(Host, Triple), TargetInitialized(false),
ARCRuntimeForSimulator(ARCSimulator_None)
{
// Compute the initial Darwin version based on the host.
bool HadExtra;
@ -70,6 +72,25 @@ bool Darwin::HasNativeLLVMSupport() const {
return true;
}
/// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0.
bool Darwin::HasARCRuntime() const {
// FIXME: Remove this once there is a proper way to detect an ARC runtime
// for the simulator.
switch (ARCRuntimeForSimulator) {
case ARCSimulator_None:
break;
case ARCSimulator_HasARCRuntime:
return true;
case ARCSimulator_NoARCRuntime:
return false;
}
if (isTargetIPhoneOS())
return !isIPhoneOSVersionLT(5);
else
return !isMacosxVersionLT(10, 7);
}
// FIXME: Can we tablegen this?
static const char *GetArmArchForMArch(llvm::StringRef Value) {
if (Value == "armv6k")
@ -320,6 +341,30 @@ void DarwinClang::AddLinkSearchPathArgs(const ArgList &Args,
CmdArgs.push_back(Args.MakeArgString("-L" + P.str()));
}
void DarwinClang::AddLinkARCArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
CmdArgs.push_back("-force_load");
llvm::sys::Path P(getDriver().ClangExecutable);
P.eraseComponent(); // 'clang'
P.eraseComponent(); // 'bin'
P.appendComponent("lib");
P.appendComponent("arc");
P.appendComponent("libarclite_");
std::string s = P.str();
// Mash in the platform.
if (isTargetIPhoneOS())
s += "iphoneos";
// FIXME: isTargetIphoneOSSimulator() is not returning true.
else if (ARCRuntimeForSimulator != ARCSimulator_None)
s += "iphonesimulator";
else
s += "macosx";
s += ".a";
CmdArgs.push_back(Args.MakeArgString(s));
}
void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
// Darwin doesn't support real static executables, don't link any runtime
@ -389,6 +434,35 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
}
}
static inline llvm::StringRef SimulatorVersionDefineName() {
return "__IPHONE_OS_VERSION_MIN_REQUIRED";
}
/// \brief Parse the simulator version define:
/// __IPHONE_OS_VERSION_MIN_REQUIRED=([0-9])([0-9][0-9])([0-9][0-9])
// and return the grouped values as integers, e.g:
// __IPHONE_OS_VERSION_MIN_REQUIRED=40201
// will return Major=4, Minor=2, Micro=1.
static bool GetVersionFromSimulatorDefine(llvm::StringRef define,
unsigned &Major, unsigned &Minor,
unsigned &Micro) {
assert(define.startswith(SimulatorVersionDefineName()));
llvm::StringRef name, version;
llvm::tie(name, version) = define.split('=');
if (version.empty())
return false;
std::string verstr = version.str();
char *end;
unsigned num = (unsigned) strtol(verstr.c_str(), &end, 10);
if (*end != '\0')
return false;
Major = num / 10000;
num = num % 10000;
Minor = num / 100;
Micro = num % 100;
return true;
}
void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
const OptTable &Opts = getDriver().getOpts();
@ -396,6 +470,27 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ);
Arg *iOSSimVersion = Args.getLastArg(
options::OPT_mios_simulator_version_min_EQ);
// FIXME: HACK! When compiling for the simulator we don't get a
// '-miphoneos-version-min' to help us know whether there is an ARC runtime
// or not; try to parse a __IPHONE_OS_VERSION_MIN_REQUIRED
// define passed in command-line.
if (!iOSVersion) {
for (arg_iterator it = Args.filtered_begin(options::OPT_D),
ie = Args.filtered_end(); it != ie; ++it) {
llvm::StringRef define = (*it)->getValue(Args);
if (define.startswith(SimulatorVersionDefineName())) {
unsigned Major, Minor, Micro;
if (GetVersionFromSimulatorDefine(define, Major, Minor, Micro) &&
Major < 10 && Minor < 100 && Micro < 100) {
ARCRuntimeForSimulator = Major < 5 ? ARCSimulator_NoARCRuntime
: ARCSimulator_HasARCRuntime;
}
break;
}
}
}
if (OSXVersion && (iOSVersion || iOSSimVersion)) {
getDriver().Diag(clang::diag::err_drv_argument_not_allowed_with)
<< OSXVersion->getAsString(Args)

View File

@ -57,6 +57,16 @@ private:
// the argument translation business.
mutable bool TargetInitialized;
// FIXME: Remove this once there is a proper way to detect an ARC runtime
// for the simulator.
public:
mutable enum {
ARCSimulator_None,
ARCSimulator_HasARCRuntime,
ARCSimulator_NoARCRuntime
} ARCRuntimeForSimulator;
private:
/// Whether we are targeting iPhoneOS target.
mutable bool TargetIsIPhoneOS;
@ -157,6 +167,10 @@ public:
virtual void AddLinkSearchPathArgs(const ArgList &Args,
ArgStringList &CmdArgs) const = 0;
/// AddLinkARCArgs - Add the linker arguments to link the ARC runtime library.
virtual void AddLinkARCArgs(const ArgList &Args,
ArgStringList &CmdArgs) const = 0;
/// AddLinkRuntimeLibArgs - Add the linker arguments to link the compiler
/// runtime library.
virtual void AddLinkRuntimeLibArgs(const ArgList &Args,
@ -170,6 +184,8 @@ public:
virtual bool HasNativeLLVMSupport() const;
virtual bool HasARCRuntime() const;
virtual DerivedArgList *TranslateArgs(const DerivedArgList &Args,
const char *BoundArch) const;
@ -257,6 +273,8 @@ public:
virtual void AddCCKextLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const;
virtual void AddLinkARCArgs(const ArgList &Args,
ArgStringList &CmdArgs) const;
/// }
};

View File

@ -30,6 +30,7 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/ErrorHandling.h"
#include "InputInfo.h"
#include "ToolChains.h"
@ -147,6 +148,12 @@ static void AddLinkerInputs(const ToolChain &TC,
}
}
/// \brief Determine whether Objective-C automated reference counting is
/// enabled.
static bool isObjCAutoRefCount(const ArgList &Args) {
return Args.hasFlag(options::OPT_fobjc_arc, options::OPT_fno_objc_arc, false);
}
static void addProfileRT(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
if (Args.hasArg(options::OPT_fprofile_arcs) ||
@ -318,8 +325,12 @@ void Clang::AddPreprocessingOptions(const Driver &D,
// Add C++ include arguments, if needed.
types::ID InputType = Inputs[0].getType();
if (types::isCXX(InputType))
getToolChain().AddClangCXXStdlibIncludeArgs(Args, CmdArgs);
if (types::isCXX(InputType)) {
bool ObjCXXAutoRefCount
= types::isObjC(InputType) && isObjCAutoRefCount(Args);
getToolChain().AddClangCXXStdlibIncludeArgs(Args, CmdArgs,
ObjCXXAutoRefCount);
}
// Add -Wp, and -Xassembler if using the preprocessor.
@ -1542,6 +1553,24 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_lax_vector_conversions))
CmdArgs.push_back("-fno-lax-vector-conversions");
// Allow -fno-objc-arr to trump -fobjc-arr/-fobjc-arc.
// NOTE: This logic is duplicated in ToolChains.cpp.
bool ARC = isObjCAutoRefCount(Args);
if (ARC) {
CmdArgs.push_back("-fobjc-arc");
// Certain deployment targets don't have runtime support.
if (!getToolChain().HasARCRuntime())
CmdArgs.push_back("-fobjc-no-arc-runtime");
// Allow the user to enable full exceptions code emission.
// We define off for Objective-CC, on for Objective-C++.
if (Args.hasFlag(options::OPT_fobjc_arc_exceptions,
options::OPT_fno_objc_arc_exceptions,
/*default*/ types::isCXX(InputType)))
CmdArgs.push_back("-fobjc-arc-exceptions");
}
// -fobjc-infer-related-result-type is the default, except in the Objective-C
// rewriter.
if (IsRewriter)
@ -1553,7 +1582,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (!GCArg)
GCArg = Args.getLastArg(options::OPT_fobjc_gc);
if (GCArg) {
if (getToolChain().SupportsObjCGC()) {
if (ARC) {
D.Diag(clang::diag::err_drv_objc_gc_arr)
<< GCArg->getAsString(Args);
} else if (getToolChain().SupportsObjCGC()) {
GCArg->render(Args, CmdArgs);
} else {
// FIXME: We should move this to a hard error.
@ -3141,6 +3173,12 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
getDarwinToolChain().AddLinkSearchPathArgs(Args, CmdArgs);
// In ARC, if we don't have runtime support, link in the runtime
// stubs. We have to do this *before* adding any of the normal
// linker inputs so that its initializer gets run first.
if (!getDarwinToolChain().HasARCRuntime() && isObjCAutoRefCount(Args))
getDarwinToolChain().AddLinkARCArgs(Args, CmdArgs);
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
if (LinkingOutput) {

View File

@ -169,6 +169,8 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
Res.push_back("-fno-use-cxa-atexit");
if (Opts.CXXCtorDtorAliases)
Res.push_back("-mconstructor-aliases");
if (Opts.ObjCAutoRefCountExceptions)
Res.push_back("-fobjc-arc-eh");
if (!Opts.DebugPass.empty()) {
Res.push_back("-mdebug-pass");
Res.push_back(Opts.DebugPass);
@ -670,6 +672,10 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-fobjc-gc-only");
}
}
if (Opts.ObjCAutoRefCount)
Res.push_back("-fobjc-arc");
if (Opts.ObjCNoAutoRefCountRuntime)
Res.push_back("-fobjc-no-arc-runtime");
if (!Opts.ObjCInferRelatedResultType)
Res.push_back("-fno-objc-infer-related-result-type");
@ -951,6 +957,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
(Opts.OptimizationLevel > 1 && !Opts.OptimizeSize);
Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose);
Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions);
Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit);
Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases);
Opts.CodeModel = Args.getLastArgValue(OPT_mcode_model);
@ -1480,17 +1487,26 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
if (Args.hasArg(OPT_fno_operator_names))
Opts.CXXOperatorNames = 0;
if (Opts.ObjC1) {
if (Args.hasArg(OPT_fobjc_gc_only))
Opts.setGCMode(LangOptions::GCOnly);
else if (Args.hasArg(OPT_fobjc_gc))
Opts.setGCMode(LangOptions::HybridGC);
else if (Args.hasArg(OPT_fobjc_arc)) {
Opts.ObjCAutoRefCount = 1;
if (!Args.hasArg(OPT_fobjc_nonfragile_abi))
Diags.Report(diag::err_arc_nonfragile_abi);
if (Args.hasArg(OPT_fobjc_no_arc_runtime))
Opts.ObjCNoAutoRefCountRuntime = 1;
}
if (Args.hasArg(OPT_fno_objc_infer_related_result_type))
Opts.ObjCInferRelatedResultType = 0;
}
if (Args.hasArg(OPT_fgnu89_inline))
Opts.GNUInline = 1;
if (Args.hasArg(OPT_fobjc_gc_only))
Opts.setGCMode(LangOptions::GCOnly);
else if (Args.hasArg(OPT_fobjc_gc))
Opts.setGCMode(LangOptions::HybridGC);
if (Args.hasArg(OPT_fno_objc_infer_related_result_type))
Opts.ObjCInferRelatedResultType = 0;
if (Args.hasArg(OPT_fapple_kext)) {
if (!Opts.CPlusPlus)
Diags.Report(diag::warn_c_kext);
@ -1715,6 +1731,19 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
Opts.addRemappedFile(Split.first, Split.second);
}
if (Arg *A = Args.getLastArg(OPT_fobjc_arc_cxxlib_EQ)) {
llvm::StringRef Name = A->getValue(Args);
unsigned Library = llvm::StringSwitch<unsigned>(Name)
.Case("libc++", ARCXX_libcxx)
.Case("libstdc++", ARCXX_libstdcxx)
.Case("none", ARCXX_nolib)
.Default(~0U);
if (Library == ~0U)
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
else
Opts.ObjCXXARCStandardLibrary = (ObjCXXARCStandardLibraryKind)Library;
}
}
static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,

View File

@ -221,6 +221,125 @@ static void DefineExactWidthIntType(TargetInfo::IntType Ty,
ConstSuffix);
}
/// \brief Add definitions required for a smooth interaction between
/// Objective-C++ automatic reference counting and libc++.
static void AddObjCXXARCLibcxxDefines(const LangOptions &LangOpts,
MacroBuilder &Builder) {
Builder.defineMacro("_LIBCPP_PREDEFINED_OBJC_ARC_ADDRESSOF");
std::string Result;
{
// Provide overloads of the function std::__1::addressof() that accept
// references to lifetime-qualified objects. libc++'s (more general)
// std::__1::addressof() template fails to instantiate with such types,
// because it attempts to convert the object to a char& before
// dereferencing.
llvm::raw_string_ostream Out(Result);
Out << "#pragma clang diagnostic push\n"
<< "#pragma clang diagnostic ignored \"-Wc++0x-extensions\"\n"
<< "namespace std { inline namespace __1 {\n"
<< "\n";
Out << "template <class _Tp>\n"
<< "inline __attribute__ ((__visibility__(\"hidden\"), "
<< "__always_inline__))\n"
<< "__attribute__((objc_lifetime(strong))) _Tp*\n"
<< "addressof(__attribute__((objc_lifetime(strong))) _Tp& __x) {\n"
<< " return &__x;\n"
<< "}\n"
<< "\n";
if (!LangOpts.ObjCNoAutoRefCountRuntime) {
Out << "template <class _Tp>\n"
<< "inline __attribute__ ((__visibility__(\"hidden\"),"
<< "__always_inline__))\n"
<< "__attribute__((objc_lifetime(weak))) _Tp*\n"
<< "addressof(__attribute__((objc_lifetime(weak))) _Tp& __x) {\n"
<< " return &__x;\n"
<< "};\n"
<< "\n";
}
Out << "template <class _Tp>\n"
<< "inline __attribute__ ((__visibility__(\"hidden\"),"
<< "__always_inline__))\n"
<< "__attribute__((objc_lifetime(autoreleasing))) _Tp*\n"
<< "addressof(__attribute__((objc_lifetime(autoreleasing))) _Tp& __x) "
<< "{\n"
<< " return &__x;\n"
<< "}\n"
<< "\n";
Out << "template <class _Tp>\n"
<< "inline __attribute__ ((__visibility__(\"hidden\"), "
<< "__always_inline__))\n"
<< "__unsafe_unretained _Tp* addressof(__unsafe_unretained _Tp& __x)"
<< " {\n"
<< " return &__x;\n"
<< "}\n";
Out << "\n"
<< "} }\n"
<< "#pragma clang diagnostic pop\n"
<< "\n";
}
Builder.append(Result);
}
/// \brief Add definitions required for a smooth interaction between
/// Objective-C++ automated reference counting and libstdc++ (4.2).
static void AddObjCXXARCLibstdcxxDefines(const LangOptions &LangOpts,
MacroBuilder &Builder) {
Builder.defineMacro("_GLIBCXX_PREDEFINED_OBJC_ARC_IS_SCALAR");
std::string Result;
{
// Provide specializations for the __is_scalar type trait so that
// lifetime-qualified objects are not considered "scalar" types, which
// libstdc++ uses as an indicator of the presence of trivial copy, assign,
// default-construct, and destruct semantics (none of which hold for
// lifetime-qualified objects in ARC).
llvm::raw_string_ostream Out(Result);
Out << "namespace std {\n"
<< "\n"
<< "struct __true_type;\n"
<< "struct __false_type;\n"
<< "\n";
Out << "template<typename _Tp> struct __is_scalar;\n"
<< "\n";
Out << "template<typename _Tp>\n"
<< "struct __is_scalar<__attribute__((objc_lifetime(strong))) _Tp> {\n"
<< " enum { __value = 0 };\n"
<< " typedef __false_type __type;\n"
<< "};\n"
<< "\n";
if (!LangOpts.ObjCNoAutoRefCountRuntime) {
Out << "template<typename _Tp>\n"
<< "struct __is_scalar<__attribute__((objc_lifetime(weak))) _Tp> {\n"
<< " enum { __value = 0 };\n"
<< " typedef __false_type __type;\n"
<< "};\n"
<< "\n";
}
Out << "template<typename _Tp>\n"
<< "struct __is_scalar<__attribute__((objc_lifetime(autoreleasing)))"
<< " _Tp> {\n"
<< " enum { __value = 0 };\n"
<< " typedef __false_type __type;\n"
<< "};\n"
<< "\n";
Out << "}\n";
}
Builder.append(Result);
}
static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
const LangOptions &LangOpts,
const FrontendOptions &FEOpts,
@ -560,6 +679,7 @@ void clang::InitializePreprocessor(Preprocessor &PP,
const PreprocessorOptions &InitOpts,
const HeaderSearchOptions &HSOpts,
const FrontendOptions &FEOpts) {
const LangOptions &LangOpts = PP.getLangOptions();
std::string PredefineBuffer;
PredefineBuffer.reserve(4080);
llvm::raw_string_ostream Predefines(PredefineBuffer);
@ -575,10 +695,27 @@ void clang::InitializePreprocessor(Preprocessor &PP,
Builder.append("# 1 \"<built-in>\" 3");
// Install things like __POWERPC__, __GNUC__, etc into the macro table.
if (InitOpts.UsePredefines)
InitializePredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(),
FEOpts, Builder);
if (InitOpts.UsePredefines) {
InitializePredefinedMacros(PP.getTargetInfo(), LangOpts, FEOpts, Builder);
// Install definitions to make Objective-C++ ARC work well with various
// C++ Standard Library implementations.
if (LangOpts.ObjC1 && LangOpts.CPlusPlus && LangOpts.ObjCAutoRefCount) {
switch (InitOpts.ObjCXXARCStandardLibrary) {
case ARCXX_nolib:
break;
case ARCXX_libcxx:
AddObjCXXARCLibcxxDefines(LangOpts, Builder);
break;
case ARCXX_libstdcxx:
AddObjCXXARCLibstdcxxDefines(LangOpts, Builder);
break;
}
}
}
// Even with predefines off, some macros are still predefined.
// These should all be defined in the preprocessor according to the
// current language configuration.

View File

@ -551,6 +551,11 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("cxx_exceptions", LangOpts.Exceptions)
.Case("cxx_rtti", LangOpts.RTTI)
.Case("enumerator_attributes", true)
// Objective-C features
.Case("objc_arr", LangOpts.ObjCAutoRefCount) // FIXME: REMOVE?
.Case("objc_arc", LangOpts.ObjCAutoRefCount)
.Case("objc_arc_weak", LangOpts.ObjCAutoRefCount &&
!LangOpts.ObjCNoAutoRefCountRuntime)
.Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI)
.Case("objc_weak_class", LangOpts.ObjCNonFragileABI)
.Case("ownership_holds", true)

View File

@ -31,9 +31,11 @@ using namespace clang;
///
/// Called type-id in C++.
TypeResult Parser::ParseTypeName(SourceRange *Range,
Declarator::TheContext Context) {
Declarator::TheContext Context,
ObjCDeclSpec *objcQuals) {
// Parse the common declaration-specifiers piece.
DeclSpec DS(AttrFactory);
DS.setObjCQualifiers(objcQuals);
ParseSpecifierQualifierList(DS);
// Parse the abstract-declarator, if present.

View File

@ -1740,7 +1740,12 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
/// '(' type-name ')' '{' initializer-list ',' '}'
/// cast-expression: [C99 6.5.4]
/// '(' type-name ')' cast-expression
///
/// [ARC] bridged-cast-expression
///
/// [ARC] bridged-cast-expression:
/// (__bridge type-name) cast-expression
/// (__bridge_transfer type-name) cast-expression
/// (__bridge_retained type-name) cast-expression
ExprResult
Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
ParsedType TypeOfCast, ParsedType &CastTy,
@ -1772,7 +1777,30 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
// If the substmt parsed correctly, build the AST node.
if (!Stmt.isInvalid())
Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.take(), Tok.getLocation());
} else if (ExprType >= CompoundLiteral &&
(Tok.is(tok::kw___bridge) ||
Tok.is(tok::kw___bridge_transfer) ||
Tok.is(tok::kw___bridge_retained))) {
// Parse an Objective-C ARC ownership cast expression.
ObjCBridgeCastKind Kind;
if (Tok.is(tok::kw___bridge))
Kind = OBC_Bridge;
else if (Tok.is(tok::kw___bridge_transfer))
Kind = OBC_BridgeTransfer;
else
Kind = OBC_BridgeRetained;
SourceLocation BridgeKeywordLoc = ConsumeToken();
TypeResult Ty = ParseTypeName();
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, OpenLoc);
ExprResult SubExpr = ParseCastExpression(false, false, ParsedType());
if (Ty.isInvalid() || SubExpr.isInvalid())
return ExprError();
return Actions.ActOnObjCBridgedCast(getCurScope(), OpenLoc, Kind,
BridgeKeywordLoc, Ty.get(),
RParenLoc, SubExpr.get());
} else if (ExprType >= CompoundLiteral &&
isTypeIdInParens(isAmbiguousTypeId)) {

View File

@ -480,6 +480,10 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl,
/// retain
/// copy
/// nonatomic
/// atomic
/// strong
/// weak
/// unsafe_unretained
///
void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl) {
assert(Tok.getKind() == tok::l_paren);
@ -504,16 +508,22 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl) {
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readonly);
else if (II->isStr("assign"))
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_assign);
else if (II->isStr("unsafe_unretained"))
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_unsafe_unretained);
else if (II->isStr("readwrite"))
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readwrite);
else if (II->isStr("retain"))
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_retain);
else if (II->isStr("strong"))
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_strong);
else if (II->isStr("copy"))
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_copy);
else if (II->isStr("nonatomic"))
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nonatomic);
else if (II->isStr("atomic"))
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_atomic);
else if (II->isStr("weak"))
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_weak);
else if (II->isStr("getter") || II->isStr("setter")) {
bool IsSetter = II->getNameStart()[0] == 's';
@ -775,11 +785,12 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS,
ParsedType Ty;
if (isTypeSpecifierQualifier()) {
TypeResult TypeSpec = ParseTypeName(0, Declarator::ObjCPrototypeContext);
TypeResult TypeSpec =
ParseTypeName(0, Declarator::ObjCPrototypeContext, &DS);
if (!TypeSpec.isInvalid())
Ty = TypeSpec.get();
}
if (Tok.is(tok::r_paren))
ConsumeParen();
else if (Tok.getLocation() == TypeStartLoc) {
@ -853,6 +864,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
}
// Now parse the selector.
SourceLocation SelectorStartLoc = Tok.getLocation();
SourceLocation selLoc;
IdentifierInfo *SelIdent = ParseObjCSelectorPiece(selLoc);
@ -1690,6 +1702,29 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
FinallyStmt.take());
}
/// objc-autoreleasepool-statement:
/// @autoreleasepool compound-statement
///
StmtResult
Parser::ParseObjCAutoreleasePoolStmt(SourceLocation atLoc) {
ConsumeToken(); // consume autoreleasepool
if (Tok.isNot(tok::l_brace)) {
Diag(Tok, diag::err_expected_lbrace);
return StmtError();
}
// Enter a scope to hold everything within the compound stmt. Compound
// statements can always hold declarations.
ParseScope BodyScope(this, Scope::DeclScope);
StmtResult AutoreleasePoolBody(ParseCompoundStatementBody());
BodyScope.Exit();
if (AutoreleasePoolBody.isInvalid())
AutoreleasePoolBody = Actions.ActOnNullStmt(Tok.getLocation());
return Actions.ActOnObjCAutoreleasePoolStmt(atLoc,
AutoreleasePoolBody.take());
}
/// objc-method-def: objc-method-proto ';'[opt] '{' body '}'
///
Decl *Parser::ParseObjCMethodDefinition() {
@ -1765,6 +1800,9 @@ StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) {
if (Tok.isObjCAtKeyword(tok::objc_synchronized))
return ParseObjCSynchronizedStmt(AtLoc);
if (Tok.isObjCAtKeyword(tok::objc_autoreleasepool))
return ParseObjCAutoreleasePoolStmt(AtLoc);
ExprResult Res(ParseExpressionWithLeadingAt(AtLoc));
if (Res.isInvalid()) {

View File

@ -121,8 +121,7 @@ void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel,
if (Hint.CodeToInsert.empty()) {
// We're removing code.
if (Rewrite.RemoveText(Hint.RemoveRange.getBegin(),
Rewrite.getRangeSize(Hint.RemoveRange)))
if (Rewrite.RemoveText(Hint.RemoveRange))
Failed = true;
continue;
}

View File

@ -231,10 +231,44 @@ RewriteBuffer &Rewriter::getEditBuffer(FileID FID) {
/// InsertText - Insert the specified string at the specified location in the
/// original buffer.
bool Rewriter::InsertText(SourceLocation Loc, llvm::StringRef Str,
bool InsertAfter) {
bool InsertAfter, bool indentNewLines) {
using llvm::StringRef;
if (!isRewritable(Loc)) return true;
FileID FID;
unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
llvm::SmallString<128> indentedStr;
if (indentNewLines && Str.find('\n') != StringRef::npos) {
StringRef MB = SourceMgr->getBufferData(FID);
unsigned lineNo = SourceMgr->getLineNumber(FID, StartOffs) - 1;
const SrcMgr::ContentCache *
Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache();
unsigned lineOffs = Content->SourceLineCache[lineNo];
// Find the whitespace at the start of the line.
StringRef indentSpace;
{
unsigned i = lineOffs;
while (isWhitespace(MB[i]))
++i;
indentSpace = MB.substr(lineOffs, i-lineOffs);
}
llvm::SmallVector<StringRef, 4> lines;
Str.split(lines, "\n");
for (unsigned i = 0, e = lines.size(); i != e; ++i) {
indentedStr += lines[i];
if (i < e-1) {
indentedStr += '\n';
indentedStr += indentSpace;
}
}
Str = indentedStr.str();
}
getEditBuffer(FID).InsertText(StartOffs, Str, InsertAfter);
return false;
}
@ -317,6 +351,7 @@ bool Rewriter::IncreaseIndentation(CharSourceRange range,
SourceLocation parentIndent) {
using llvm::StringRef;
if (range.isInvalid()) return true;
if (!isRewritable(range.getBegin())) return true;
if (!isRewritable(range.getEnd())) return true;
if (!isRewritable(parentIndent)) return true;
@ -330,7 +365,7 @@ bool Rewriter::IncreaseIndentation(CharSourceRange range,
if (StartFileID != EndFileID || StartFileID != parentFileID)
return true;
if (StartOff >= EndOff || parentOff >= StartOff)
if (StartOff > EndOff)
return true;
FileID FID = StartFileID;
@ -343,16 +378,12 @@ bool Rewriter::IncreaseIndentation(CharSourceRange range,
const SrcMgr::ContentCache *
Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache();
// Find where the line starts for the three offsets.
// Find where the lines start.
unsigned parentLineOffs = Content->SourceLineCache[parentLineNo];
unsigned startLineOffs = Content->SourceLineCache[startLineNo];
unsigned endLineOffs = Content->SourceLineCache[endLineNo];
if (startLineOffs == endLineOffs || startLineOffs == parentLineOffs)
return true;
// Find the whitespace at the start of each line.
StringRef parentSpace, startSpace, endSpace;
StringRef parentSpace, startSpace;
{
unsigned i = parentLineOffs;
while (isWhitespace(MB[i]))
@ -363,11 +394,6 @@ bool Rewriter::IncreaseIndentation(CharSourceRange range,
while (isWhitespace(MB[i]))
++i;
startSpace = MB.substr(startLineOffs, i-startLineOffs);
i = endLineOffs;
while (isWhitespace(MB[i]))
++i;
endSpace = MB.substr(endLineOffs, i-endLineOffs);
}
if (parentSpace.size() >= startSpace.size())
return true;
@ -378,19 +404,14 @@ bool Rewriter::IncreaseIndentation(CharSourceRange range,
// Indent the lines between start/end offsets.
RewriteBuffer &RB = getEditBuffer(FID);
for (unsigned i = startLineOffs; i != endLineOffs; ++i) {
if (MB[i] == '\n') {
unsigned startOfLine = i+1;
if (startOfLine == endLineOffs)
break;
StringRef origIndent;
unsigned ws = startOfLine;
while (isWhitespace(MB[ws]))
++ws;
origIndent = MB.substr(startOfLine, ws-startOfLine);
if (origIndent.startswith(startSpace))
RB.InsertText(startOfLine, indent, /*InsertAfter=*/false);
}
for (unsigned lineNo = startLineNo; lineNo <= endLineNo; ++lineNo) {
unsigned offs = Content->SourceLineCache[lineNo];
unsigned i = offs;
while (isWhitespace(MB[i]))
++i;
StringRef origIndent = MB.substr(offs, i-offs);
if (origIndent.startswith(startSpace))
RB.InsertText(offs, indent, /*InsertAfter=*/false);
}
return false;

View File

@ -177,6 +177,11 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
.Case("cf_consumed", AT_cf_consumed)
.Case("cf_returns_not_retained", AT_cf_returns_not_retained)
.Case("cf_returns_retained", AT_cf_returns_retained)
.Case("cf_returns_autoreleased", AT_cf_returns_autoreleased)
.Case("ns_consumes_self", AT_ns_consumes_self)
.Case("ns_consumed", AT_ns_consumed)
.Case("objc_lifetime", AT_objc_lifetime)
.Case("objc_precise_lifetime", AT_objc_precise_lifetime)
.Case("ownership_returns", AT_ownership_returns)
.Case("ownership_holds", AT_ownership_holds)
.Case("ownership_takes", AT_ownership_takes)

View File

@ -47,5 +47,8 @@ void DelayedDiagnostic::Destroy() {
case Deprecation:
delete [] DeprecationData.Message;
break;
case ForbiddenType:
break;
}
}

View File

@ -111,90 +111,110 @@ unsigned JumpScopeChecker::GetDeepestCommonScope(unsigned A, unsigned B) {
return A;
}
typedef std::pair<unsigned,unsigned> ScopePair;
/// GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a
/// diagnostic that should be emitted if control goes over it. If not, return 0.
static std::pair<unsigned,unsigned>
GetDiagForGotoScopeDecl(const Decl *D, bool isCPlusPlus) {
static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
unsigned InDiag = 0, OutDiag = 0;
if (VD->getType()->isVariablyModifiedType())
InDiag = diag::note_protected_by_vla;
if (VD->hasAttr<BlocksAttr>()) {
InDiag = diag::note_protected_by___block;
OutDiag = diag::note_exits___block;
} else if (VD->hasAttr<CleanupAttr>()) {
InDiag = diag::note_protected_by_cleanup;
OutDiag = diag::note_exits_cleanup;
} else if (isCPlusPlus) {
if (!VD->hasLocalStorage())
return std::make_pair(InDiag, OutDiag);
ASTContext &Context = D->getASTContext();
QualType T = Context.getBaseElementType(VD->getType());
if (!T->isDependentType()) {
// C++0x [stmt.dcl]p3:
// A program that jumps from a point where a variable with automatic
// storage duration is not in scope to a point where it is in scope
// is ill-formed unless the variable has scalar type, class type with
// a trivial default constructor and a trivial destructor, a
// cv-qualified version of one of these types, or an array of one of
// the preceding types and is declared without an initializer (8.5).
// Check whether this is a C++ class.
CXXRecordDecl *Record = T->getAsCXXRecordDecl();
if (const Expr *Init = VD->getInit()) {
bool CallsTrivialConstructor = false;
if (Record) {
// FIXME: With generalized initializer lists, this may
// classify "X x{};" as having no initializer.
if (const CXXConstructExpr *Construct
= dyn_cast<CXXConstructExpr>(Init))
if (const CXXConstructorDecl *Constructor
= Construct->getConstructor())
if ((Context.getLangOptions().CPlusPlus0x
? Record->hasTrivialDefaultConstructor()
: Record->isPOD()) &&
Constructor->isDefaultConstructor())
CallsTrivialConstructor = true;
if (CallsTrivialConstructor && !Record->hasTrivialDestructor())
InDiag = diag::note_protected_by_variable_nontriv_destructor;
if (VD->hasAttr<BlocksAttr>())
return ScopePair(diag::note_protected_by___block,
diag::note_exits___block);
if (VD->hasAttr<CleanupAttr>())
return ScopePair(diag::note_protected_by_cleanup,
diag::note_exits_cleanup);
if (Context.getLangOptions().ObjCAutoRefCount && VD->hasLocalStorage()) {
switch (VD->getType().getObjCLifetime()) {
case Qualifiers::OCL_None:
case Qualifiers::OCL_ExplicitNone:
case Qualifiers::OCL_Autoreleasing:
break;
case Qualifiers::OCL_Strong:
case Qualifiers::OCL_Weak:
return ScopePair(diag::note_protected_by_objc_lifetime,
diag::note_exits_objc_lifetime);
}
}
if (Context.getLangOptions().CPlusPlus && VD->hasLocalStorage()) {
// C++0x [stmt.dcl]p3:
// A program that jumps from a point where a variable with automatic
// storage duration is not in scope to a point where it is in scope
// is ill-formed unless the variable has scalar type, class type with
// a trivial default constructor and a trivial destructor, a
// cv-qualified version of one of these types, or an array of one of
// the preceding types and is declared without an initializer.
// C++03 [stmt.dcl.p3:
// A program that jumps from a point where a local variable
// with automatic storage duration is not in scope to a point
// where it is in scope is ill-formed unless the variable has
// POD type and is declared without an initializer.
if (const Expr *init = VD->getInit()) {
// We actually give variables of record type (or array thereof)
// an initializer even if that initializer only calls a trivial
// ctor. Detect that case.
// FIXME: With generalized initializer lists, this may
// classify "X x{};" as having no initializer.
unsigned inDiagToUse = diag::note_protected_by_variable_init;
const CXXRecordDecl *record = 0;
if (const CXXConstructExpr *cce = dyn_cast<CXXConstructExpr>(init)) {
const CXXConstructorDecl *ctor = cce->getConstructor();
record = ctor->getParent();
if (ctor->isTrivial() && ctor->isDefaultConstructor()) {
if (Context.getLangOptions().CPlusPlus0x) {
inDiagToUse = (record->hasTrivialDestructor() ? 0 :
diag::note_protected_by_variable_nontriv_destructor);
} else {
if (record->isPOD())
inDiagToUse = 0;
}
}
if (!CallsTrivialConstructor)
InDiag = diag::note_protected_by_variable_init;
} else if (VD->getType()->isArrayType()) {
record = VD->getType()->getBaseElementTypeUnsafe()
->getAsCXXRecordDecl();
}
// Note whether we have a class with a non-trivial destructor.
if (Record && !Record->hasTrivialDestructor())
if (inDiagToUse)
InDiag = inDiagToUse;
// Also object to indirect jumps which leave scopes with dtors.
if (record && !record->hasTrivialDestructor())
OutDiag = diag::note_exits_dtor;
}
}
return std::make_pair(InDiag, OutDiag);
return ScopePair(InDiag, OutDiag);
}
if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
if (TD->getUnderlyingType()->isVariablyModifiedType())
return std::make_pair((unsigned) diag::note_protected_by_vla_typedef, 0);
return ScopePair(diag::note_protected_by_vla_typedef, 0);
}
if (const TypeAliasDecl *TD = dyn_cast<TypeAliasDecl>(D)) {
if (TD->getUnderlyingType()->isVariablyModifiedType())
return std::make_pair((unsigned) diag::note_protected_by_vla_type_alias, 0);
return ScopePair(diag::note_protected_by_vla_type_alias, 0);
}
return std::make_pair(0U, 0U);
return ScopePair(0U, 0U);
}
/// \brief Build scope information for a declaration that is part of a DeclStmt.
void JumpScopeChecker::BuildScopeInformation(Decl *D, unsigned &ParentScope) {
bool isCPlusPlus = this->S.getLangOptions().CPlusPlus;
// If this decl causes a new scope, push and switch to it.
std::pair<unsigned,unsigned> Diags
= GetDiagForGotoScopeDecl(D, isCPlusPlus);
std::pair<unsigned,unsigned> Diags = GetDiagForGotoScopeDecl(S.Context, D);
if (Diags.first || Diags.second) {
Scopes.push_back(GotoScope(ParentScope, Diags.first, Diags.second,
D->getLocation()));
@ -369,6 +389,18 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
continue;
}
// Disallow jumps into the protected statement of an @autoreleasepool.
if (ObjCAutoreleasePoolStmt *AS = dyn_cast<ObjCAutoreleasePoolStmt>(SubStmt)){
// Recursively walk the AST for the @autoreleasepool part, protected by a new
// scope.
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_objc_autoreleasepool,
diag::note_exits_objc_autoreleasepool,
AS->getAtLoc()));
BuildScopeInformation(AS->getSubStmt(), Scopes.size()-1);
continue;
}
// Recursively walk the AST.
BuildScopeInformation(SubStmt, ParentScope);
}

View File

@ -143,7 +143,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0),
PackContext(0), MSStructPragmaOn(false), VisContext(0),
LateTemplateParser(0), OpaqueParser(0),
ExprNeedsCleanups(0), LateTemplateParser(0), OpaqueParser(0),
IdResolver(pp.getLangOptions()), CXXTypeInfoDecl(0), MSVCGuidDecl(0),
GlobalNewDeleteDeclared(false),
CompleteTranslationUnit(CompleteTranslationUnit),
@ -162,7 +162,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
&Context);
ExprEvalContexts.push_back(
ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0));
ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0, false));
FunctionScopes.push_back(new FunctionScopeInfo(Diags));
}
@ -202,6 +202,32 @@ Sema::~Sema() {
ExternalSema->ForgetSema();
}
/// makeUnavailableInSystemHeader - There is an error in the current
/// context. If we're still in a system header, and we can plausibly
/// make the relevant declaration unavailable instead of erroring, do
/// so and return true.
bool Sema::makeUnavailableInSystemHeader(SourceLocation loc,
llvm::StringRef msg) {
// If we're not in a function, it's an error.
FunctionDecl *fn = dyn_cast<FunctionDecl>(CurContext);
if (!fn) return false;
// If we're in template instantiation, it's an error.
if (!ActiveTemplateInstantiations.empty())
return false;
// If that function's not in a system header, it's an error.
if (!Context.getSourceManager().isInSystemHeader(loc))
return false;
// If the function is already unavailable, it's not an error.
if (fn->hasAttr<UnavailableAttr>()) return true;
fn->addAttr(new (Context) UnavailableAttr(loc, Context, msg));
return true;
}
ASTMutationListener *Sema::getASTMutationListener() const {
return getASTConsumer().GetASTMutationListener();
}
@ -211,13 +237,17 @@ ASTMutationListener *Sema::getASTMutationListener() const {
/// The result is of the given category.
ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
CastKind Kind, ExprValueKind VK,
const CXXCastPath *BasePath) {
const CXXCastPath *BasePath,
CheckedConversionKind CCK) {
QualType ExprTy = Context.getCanonicalType(E->getType());
QualType TypeTy = Context.getCanonicalType(Ty);
if (ExprTy == TypeTy)
return Owned(E);
if (getLangOptions().ObjCAutoRefCount)
CheckObjCARCConversion(SourceRange(), Ty, E, CCK);
// If this is a derived-to-base cast to a through a virtual base, we
// need a vtable.
if (Kind == CK_DerivedToBase &&
@ -729,8 +759,8 @@ void Sema::PopFunctionOrBlockScope(const AnalysisBasedWarnings::Policy *WP,
/// \brief Determine whether any errors occurred within this function/method/
/// block.
bool Sema::hasAnyErrorsInThisFunction() const {
return getCurFunction()->ErrorTrap.hasErrorOccurred();
bool Sema::hasAnyUnrecoverableErrorsInThisFunction() const {
return getCurFunction()->ErrorTrap.hasUnrecoverableErrorOccurred();
}
BlockScopeInfo *Sema::getCurBlock() {

View File

@ -63,7 +63,8 @@ static void CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
CastKind &Kind,
CXXCastPath &BasePath);
static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType);
static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
bool CheckCVR, bool CheckObjCLifetime);
// The Try functions attempt a specific way of casting. If they succeed, they
// return TC_Success. If their way of casting is not appropriate for the given
@ -109,12 +110,14 @@ static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExp
CXXCastPath &BasePath);
static TryCastResult TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
QualType DestType,
Sema::CheckedConversionKind CCK,
const SourceRange &OpRange,
unsigned &msg,
CastKind &Kind);
static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
QualType DestType,
Sema::CheckedConversionKind CCK,
const SourceRange &OpRange,
unsigned &msg,
CastKind &Kind,
@ -248,8 +251,10 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
InitializedEntity entity = InitializedEntity::InitializeTemporary(destType);
InitializationKind initKind
= InitializationKind::CreateCast(/*type range?*/ range,
(CT == CT_CStyle || CT == CT_Functional));
= (CT == CT_CStyle)? InitializationKind::CreateCStyleCast(range.getBegin(),
range)
: (CT == CT_Functional)? InitializationKind::CreateFunctionalCast(range)
: InitializationKind::CreateCast(/*type range?*/ range);
InitializationSequence sequence(S, entity, initKind, &src, 1);
assert(sequence.Failed() && "initialization succeeded on second try?");
@ -373,8 +378,19 @@ static bool UnwrapDissimilarPointerTypes(QualType& T1, QualType& T2) {
/// DestType casts away constness as defined in C++ 5.2.11p8ff. This is used by
/// the cast checkers. Both arguments must denote pointer (possibly to member)
/// types.
///
/// \param CheckCVR Whether to check for const/volatile/restrict qualifiers.
///
/// \param CheckObjCLifetime Whether to check Objective-C lifetime qualifiers.
static bool
CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) {
CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
bool CheckCVR, bool CheckObjCLifetime) {
// If the only checking we care about is for Objective-C lifetime qualifiers,
// and we're not in ARC mode, there's nothing to check.
if (!CheckCVR && CheckObjCLifetime &&
!Self.Context.getLangOptions().ObjCAutoRefCount)
return false;
// Casting away constness is defined in C++ 5.2.11p8 with reference to
// C++ 4.4. We piggyback on Sema::IsQualificationConversion for this, since
// the rules are non-trivial. So first we construct Tcv *...cv* as described
@ -394,13 +410,23 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) {
// purpose of this check, because other qualifiers (address spaces,
// Objective-C GC, etc.) are part of the type's identity.
while (UnwrapDissimilarPointerTypes(UnwrappedSrcType, UnwrappedDestType)) {
Qualifiers SrcQuals;
// Determine the relevant qualifiers at this level.
Qualifiers SrcQuals, DestQuals;
Self.Context.getUnqualifiedArrayType(UnwrappedSrcType, SrcQuals);
cv1.push_back(Qualifiers::fromCVRMask(SrcQuals.getCVRQualifiers()));
Qualifiers DestQuals;
Self.Context.getUnqualifiedArrayType(UnwrappedDestType, DestQuals);
cv2.push_back(Qualifiers::fromCVRMask(DestQuals.getCVRQualifiers()));
Qualifiers RetainedSrcQuals, RetainedDestQuals;
if (CheckCVR) {
RetainedSrcQuals.setCVRQualifiers(SrcQuals.getCVRQualifiers());
RetainedDestQuals.setCVRQualifiers(DestQuals.getCVRQualifiers());
}
if (CheckObjCLifetime &&
!DestQuals.compatiblyIncludesObjCLifetime(SrcQuals))
return true;
cv1.push_back(RetainedSrcQuals);
cv2.push_back(RetainedDestQuals);
}
if (cv1.empty())
return false;
@ -420,8 +446,10 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) {
}
// Test if they're compatible.
bool ObjCLifetimeConversion;
return SrcConstruct != DestConstruct &&
!Self.IsQualificationConversion(SrcConstruct, DestConstruct, false);
!Self.IsQualificationConversion(SrcConstruct, DestConstruct, false,
ObjCLifetimeConversion);
}
/// CheckDynamicCast - Check that a dynamic_cast\<DestType\>(SrcExpr) is valid.
@ -595,9 +623,10 @@ CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
}
unsigned msg = diag::err_bad_cxx_cast_generic;
if (TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange,
msg, Kind)
!= TC_Success && msg != 0)
TryCastResult tcr =
TryReinterpretCast(Self, SrcExpr, DestType,
/*CStyle*/false, OpRange, msg, Kind);
if (tcr != TC_Success && msg != 0)
{
if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
return;
@ -611,7 +640,10 @@ CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
} else {
diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(), DestType);
}
}
} else if (tcr == TC_Success && Self.getLangOptions().ObjCAutoRefCount) {
Self.CheckObjCARCConversion(OpRange, DestType,
SrcExpr.get(), Sema::CCK_OtherCast);
}
}
@ -654,8 +686,10 @@ CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
}
unsigned msg = diag::err_bad_cxx_cast_generic;
if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg,
Kind, BasePath) != TC_Success && msg != 0) {
TryCastResult tcr
= TryStaticCast(Self, SrcExpr, DestType, Sema::CCK_OtherCast, OpRange, msg,
Kind, BasePath);
if (tcr != TC_Success && msg != 0) {
if (SrcExpr.isInvalid())
return;
if (SrcExpr.get()->getType() == Self.Context.OverloadTy) {
@ -667,6 +701,12 @@ CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
} else {
diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr.get(), DestType);
}
} else if (tcr == TC_Success) {
if (Kind == CK_BitCast)
Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange);
if (Self.getLangOptions().ObjCAutoRefCount)
Self.CheckObjCARCConversion(OpRange, DestType,
SrcExpr.get(), Sema::CCK_OtherCast);
}
else if (Kind == CK_BitCast)
Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange);
@ -676,10 +716,15 @@ CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
/// possible. If @p CStyle, ignore access restrictions on hierarchy casting
/// and casting away constness.
static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
QualType DestType,
Sema::CheckedConversionKind CCK,
const SourceRange &OpRange, unsigned &msg,
CastKind &Kind,
CXXCastPath &BasePath) {
// Determine whether we have the semantics of a C-style cast.
bool CStyle
= (CCK == Sema::CCK_CStyleCast || CCK == Sema::CCK_FunctionalCast);
// The order the tests is not entirely arbitrary. There is one conversion
// that can be handled in two different ways. Given:
// struct A {};
@ -715,7 +760,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
// C++ 5.2.9p2: An expression e can be explicitly converted to a type T
// [...] if the declaration "T t(e);" is well-formed, [...].
tcr = TryStaticImplicitCast(Self, SrcExpr, DestType, CStyle, OpRange, msg,
tcr = TryStaticImplicitCast(Self, SrcExpr, DestType, CCK, OpRange, msg,
Kind);
if (SrcExpr.isInvalid())
return TC_Failed;
@ -792,10 +837,20 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
QualType DestPointee = DestPointer->getPointeeType();
if (DestPointee->isIncompleteOrObjectType()) {
// This is definitely the intended conversion, but it might fail due
// to a const violation.
if (!CStyle && !DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) {
msg = diag::err_bad_cxx_cast_qualifiers_away;
return TC_Failed;
// to a qualifier violation. Note that we permit Objective-C lifetime
// and GC qualifier mismatches here.
if (!CStyle) {
Qualifiers DestPointeeQuals = DestPointee.getQualifiers();
Qualifiers SrcPointeeQuals = SrcPointee.getQualifiers();
DestPointeeQuals.removeObjCGCAttr();
DestPointeeQuals.removeObjCLifetime();
SrcPointeeQuals.removeObjCGCAttr();
SrcPointeeQuals.removeObjCLifetime();
if (DestPointeeQuals != SrcPointeeQuals &&
!DestPointeeQuals.compatiblyIncludes(SrcPointeeQuals)) {
msg = diag::err_bad_cxx_cast_qualifiers_away;
return TC_Failed;
}
}
Kind = CK_BitCast;
return TC_Success;
@ -845,6 +900,7 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType,
// FIXME: Should allow casting away constness if CStyle.
bool DerivedToBase;
bool ObjCConversion;
bool ObjCLifetimeConversion;
QualType FromType = SrcExpr->getType();
QualType ToType = R->getPointeeType();
if (CStyle) {
@ -854,8 +910,9 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType,
if (Self.CompareReferenceRelationship(SrcExpr->getLocStart(),
ToType, FromType,
DerivedToBase, ObjCConversion) <
Sema::Ref_Compatible_With_Added_Qualification) {
DerivedToBase, ObjCConversion,
ObjCLifetimeConversion)
< Sema::Ref_Compatible_With_Added_Qualification) {
msg = diag::err_bad_lvalue_to_rvalue_cast;
return TC_Failed;
}
@ -1172,7 +1229,8 @@ TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr, QualType SrcType,
/// @c static_cast if the declaration "T t(e);" is well-formed [...].
TryCastResult
TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
bool CStyle, const SourceRange &OpRange, unsigned &msg,
Sema::CheckedConversionKind CCK,
const SourceRange &OpRange, unsigned &msg,
CastKind &Kind) {
if (DestType->isRecordType()) {
if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
@ -1184,7 +1242,11 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType);
InitializationKind InitKind
= InitializationKind::CreateCast(/*FIXME:*/OpRange, CStyle);
= (CCK == Sema::CCK_CStyleCast)
? InitializationKind::CreateCStyleCast(OpRange.getBegin(), OpRange)
: (CCK == Sema::CCK_FunctionalCast)
? InitializationKind::CreateFunctionalCast(OpRange)
: InitializationKind::CreateCast(OpRange);
Expr *SrcExprRaw = SrcExpr.get();
InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExprRaw, 1);
@ -1193,7 +1255,8 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
// There is no other way that works.
// On the other hand, if we're checking a C-style cast, we've still got
// the reinterpret_cast way.
bool CStyle
= (CCK == Sema::CCK_CStyleCast || CCK == Sema::CCK_FunctionalCast);
if (InitSeq.Failed() && (CStyle || !DestType->isReferenceType()))
return TC_NotApplicable;
@ -1428,7 +1491,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
// constness.
// A reinterpret_cast followed by a const_cast can, though, so in C-style,
// we accept it.
if (!CStyle && CastsAwayConstness(Self, SrcType, DestType)) {
if (CastsAwayConstness(Self, SrcType, DestType, /*CheckCVR=*/!CStyle,
/*CheckObjCLifetime=*/CStyle)) {
msg = diag::err_bad_cxx_cast_qualifiers_away;
return TC_Failed;
}
@ -1543,7 +1607,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
// C++ 5.2.10p2: The reinterpret_cast operator shall not cast away constness.
// The C-style cast operator can.
if (!CStyle && CastsAwayConstness(Self, SrcType, DestType)) {
if (CastsAwayConstness(Self, SrcType, DestType, /*CheckCVR=*/!CStyle,
/*CheckObjCLifetime=*/CStyle)) {
msg = diag::err_bad_cxx_cast_qualifiers_away;
return TC_Failed;
}
@ -1675,11 +1740,14 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
if (tcr == TC_Success)
Kind = CK_NoOp;
Sema::CheckedConversionKind CCK
= FunctionalStyle? Sema::CCK_FunctionalCast
: Sema::CCK_CStyleCast;
if (tcr == TC_NotApplicable) {
// ... or if that is not possible, a static_cast, ignoring const, ...
ExprResult CastExprRes = Owned(CastExpr);
tcr = TryStaticCast(*this, CastExprRes, CastTy, /*CStyle*/true, R, msg,
Kind, BasePath);
tcr = TryStaticCast(*this, CastExprRes, CastTy, CCK, R, msg, Kind,
BasePath);
if (CastExprRes.isInvalid())
return ExprError();
CastExpr = CastExprRes.take();
@ -1694,6 +1762,9 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
}
}
if (getLangOptions().ObjCAutoRefCount && tcr == TC_Success)
CheckObjCARCConversion(R, CastTy, CastExpr, CCK);
if (tcr != TC_Success && msg != 0) {
if (CastExpr->getType() == Context.OverloadTy) {
DeclAccessPair Found;

View File

@ -22,6 +22,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
@ -382,14 +383,14 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
// casts here.
// FIXME: We don't allow floating point scalars as input.
Expr *FirstArg = TheCall->getArg(0);
if (!FirstArg->getType()->isPointerType()) {
const PointerType *pointerType = FirstArg->getType()->getAs<PointerType>();
if (!pointerType) {
Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer)
<< FirstArg->getType() << FirstArg->getSourceRange();
return ExprError();
}
QualType ValType =
FirstArg->getType()->getAs<PointerType>()->getPointeeType();
QualType ValType = pointerType->getPointeeType();
if (!ValType->isIntegerType() && !ValType->isAnyPointerType() &&
!ValType->isBlockPointerType()) {
Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer_intptr)
@ -397,6 +398,20 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
return ExprError();
}
switch (ValType.getObjCLifetime()) {
case Qualifiers::OCL_None:
case Qualifiers::OCL_ExplicitNone:
// okay
break;
case Qualifiers::OCL_Weak:
case Qualifiers::OCL_Strong:
case Qualifiers::OCL_Autoreleasing:
Diag(DRE->getLocStart(), diag::err_arc_atomic_lifetime)
<< ValType << FirstArg->getSourceRange();
return ExprError();
}
// The majority of builtins return a value, but a few have special return
// types, so allow them to override appropriately below.
QualType ResultType = ValType;
@ -518,7 +533,8 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
CastKind Kind = CK_Invalid;
ExprValueKind VK = VK_RValue;
CXXCastPath BasePath;
Arg = CheckCastTypes(Arg.get()->getSourceRange(), ValType, Arg.take(), Kind, VK, BasePath);
Arg = CheckCastTypes(Arg.get()->getLocStart(), Arg.get()->getSourceRange(),
ValType, Arg.take(), Kind, VK, BasePath);
if (Arg.isInvalid())
return ExprError();
@ -1849,6 +1865,7 @@ void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call,
QualType DestTy = Dest->getType();
if (const PointerType *DestPtrTy = DestTy->getAs<PointerType>()) {
QualType PointeeTy = DestPtrTy->getPointeeType();
if (PointeeTy->isVoidType())
continue;
@ -1863,16 +1880,22 @@ void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call,
break;
}
unsigned DiagID;
// Always complain about dynamic classes.
if (isDynamicClassType(PointeeTy)) {
DiagRuntimeBehavior(
Dest->getExprLoc(), Dest,
PDiag(diag::warn_dyn_class_memaccess)
<< ArgIdx << FnName << PointeeTy
<< Call->getCallee()->getSourceRange());
} else {
if (isDynamicClassType(PointeeTy))
DiagID = diag::warn_dyn_class_memaccess;
else if (PointeeTy.hasNonTrivialObjCLifetime() &&
!FnName->isStr("memset"))
DiagID = diag::warn_arc_object_memaccess;
else
continue;
}
DiagRuntimeBehavior(
Dest->getExprLoc(), Dest,
PDiag(DiagID)
<< ArgIdx << FnName << PointeeTy
<< Call->getCallee()->getSourceRange());
DiagRuntimeBehavior(
Dest->getExprLoc(), Dest,
@ -1899,7 +1922,8 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
// Perform checking for returned stack addresses, local blocks,
// label addresses or references to temporaries.
if (lhsType->isPointerType() || lhsType->isBlockPointerType()) {
if (lhsType->isPointerType() ||
(!getLangOptions().ObjCAutoRefCount && lhsType->isBlockPointerType())) {
stackE = EvalAddr(RetValExp, refVars);
} else if (lhsType->isReferenceType()) {
stackE = EvalVal(RetValExp, refVars);
@ -2070,7 +2094,8 @@ static Expr *EvalAddr(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars) {
// pointer values, and pointer-to-pointer conversions.
case Stmt::ImplicitCastExprClass:
case Stmt::CStyleCastExprClass:
case Stmt::CXXFunctionalCastExprClass: {
case Stmt::CXXFunctionalCastExprClass:
case Stmt::ObjCBridgedCastExprClass: {
Expr* SubExpr = cast<CastExpr>(E)->getSubExpr();
QualType T = SubExpr->getType();
@ -3385,3 +3410,232 @@ void Sema::CheckArrayAccess(const Expr *expr) {
}
}
}
//===--- CHECK: Objective-C retain cycles ----------------------------------//
namespace {
struct RetainCycleOwner {
RetainCycleOwner() : Variable(0), Indirect(false) {}
VarDecl *Variable;
SourceRange Range;
SourceLocation Loc;
bool Indirect;
void setLocsFrom(Expr *e) {
Loc = e->getExprLoc();
Range = e->getSourceRange();
}
};
}
/// Consider whether capturing the given variable can possibly lead to
/// a retain cycle.
static bool considerVariable(VarDecl *var, Expr *ref, RetainCycleOwner &owner) {
// In ARC, it's captured strongly iff the variable has __strong
// lifetime. In MRR, it's captured strongly if the variable is
// __block and has an appropriate type.
if (var->getType().getObjCLifetime() != Qualifiers::OCL_Strong)
return false;
owner.Variable = var;
owner.setLocsFrom(ref);
return true;
}
static bool findRetainCycleOwner(Expr *e, RetainCycleOwner &owner) {
while (true) {
e = e->IgnoreParens();
if (CastExpr *cast = dyn_cast<CastExpr>(e)) {
switch (cast->getCastKind()) {
case CK_BitCast:
case CK_LValueBitCast:
case CK_LValueToRValue:
e = cast->getSubExpr();
continue;
case CK_GetObjCProperty: {
// Bail out if this isn't a strong explicit property.
const ObjCPropertyRefExpr *pre = cast->getSubExpr()->getObjCProperty();
if (pre->isImplicitProperty()) return false;
ObjCPropertyDecl *property = pre->getExplicitProperty();
if (!(property->getPropertyAttributes() &
(ObjCPropertyDecl::OBJC_PR_retain |
ObjCPropertyDecl::OBJC_PR_copy |
ObjCPropertyDecl::OBJC_PR_strong)) &&
!(property->getPropertyIvarDecl() &&
property->getPropertyIvarDecl()->getType()
.getObjCLifetime() == Qualifiers::OCL_Strong))
return false;
owner.Indirect = true;
e = const_cast<Expr*>(pre->getBase());
continue;
}
default:
return false;
}
}
if (ObjCIvarRefExpr *ref = dyn_cast<ObjCIvarRefExpr>(e)) {
ObjCIvarDecl *ivar = ref->getDecl();
if (ivar->getType().getObjCLifetime() != Qualifiers::OCL_Strong)
return false;
// Try to find a retain cycle in the base.
if (!findRetainCycleOwner(ref->getBase(), owner))
return false;
if (ref->isFreeIvar()) owner.setLocsFrom(ref);
owner.Indirect = true;
return true;
}
if (DeclRefExpr *ref = dyn_cast<DeclRefExpr>(e)) {
VarDecl *var = dyn_cast<VarDecl>(ref->getDecl());
if (!var) return false;
return considerVariable(var, ref, owner);
}
if (BlockDeclRefExpr *ref = dyn_cast<BlockDeclRefExpr>(e)) {
owner.Variable = ref->getDecl();
owner.setLocsFrom(ref);
return true;
}
if (MemberExpr *member = dyn_cast<MemberExpr>(e)) {
if (member->isArrow()) return false;
// Don't count this as an indirect ownership.
e = member->getBase();
continue;
}
// Array ivars?
return false;
}
}
namespace {
struct FindCaptureVisitor : EvaluatedExprVisitor<FindCaptureVisitor> {
FindCaptureVisitor(ASTContext &Context, VarDecl *variable)
: EvaluatedExprVisitor<FindCaptureVisitor>(Context),
Variable(variable), Capturer(0) {}
VarDecl *Variable;
Expr *Capturer;
void VisitDeclRefExpr(DeclRefExpr *ref) {
if (ref->getDecl() == Variable && !Capturer)
Capturer = ref;
}
void VisitBlockDeclRefExpr(BlockDeclRefExpr *ref) {
if (ref->getDecl() == Variable && !Capturer)
Capturer = ref;
}
void VisitObjCIvarRefExpr(ObjCIvarRefExpr *ref) {
if (Capturer) return;
Visit(ref->getBase());
if (Capturer && ref->isFreeIvar())
Capturer = ref;
}
void VisitBlockExpr(BlockExpr *block) {
// Look inside nested blocks
if (block->getBlockDecl()->capturesVariable(Variable))
Visit(block->getBlockDecl()->getBody());
}
};
}
/// Check whether the given argument is a block which captures a
/// variable.
static Expr *findCapturingExpr(Sema &S, Expr *e, RetainCycleOwner &owner) {
assert(owner.Variable && owner.Loc.isValid());
e = e->IgnoreParenCasts();
BlockExpr *block = dyn_cast<BlockExpr>(e);
if (!block || !block->getBlockDecl()->capturesVariable(owner.Variable))
return 0;
FindCaptureVisitor visitor(S.Context, owner.Variable);
visitor.Visit(block->getBlockDecl()->getBody());
return visitor.Capturer;
}
static void diagnoseRetainCycle(Sema &S, Expr *capturer,
RetainCycleOwner &owner) {
assert(capturer);
assert(owner.Variable && owner.Loc.isValid());
S.Diag(capturer->getExprLoc(), diag::warn_arc_retain_cycle)
<< owner.Variable << capturer->getSourceRange();
S.Diag(owner.Loc, diag::note_arc_retain_cycle_owner)
<< owner.Indirect << owner.Range;
}
/// Check for a keyword selector that starts with the word 'add' or
/// 'set'.
static bool isSetterLikeSelector(Selector sel) {
if (sel.isUnarySelector()) return false;
llvm::StringRef str = sel.getNameForSlot(0);
while (!str.empty() && str.front() == '_') str = str.substr(1);
if (str.startswith("set") || str.startswith("add"))
str = str.substr(3);
else
return false;
if (str.empty()) return true;
return !islower(str.front());
}
/// Check a message send to see if it's likely to cause a retain cycle.
void Sema::checkRetainCycles(ObjCMessageExpr *msg) {
// Only check instance methods whose selector looks like a setter.
if (!msg->isInstanceMessage() || !isSetterLikeSelector(msg->getSelector()))
return;
// Try to find a variable that the receiver is strongly owned by.
RetainCycleOwner owner;
if (msg->getReceiverKind() == ObjCMessageExpr::Instance) {
if (!findRetainCycleOwner(msg->getInstanceReceiver(), owner))
return;
} else {
assert(msg->getReceiverKind() == ObjCMessageExpr::SuperInstance);
owner.Variable = getCurMethodDecl()->getSelfDecl();
owner.Loc = msg->getSuperLoc();
owner.Range = msg->getSuperLoc();
}
// Check whether the receiver is captured by any of the arguments.
for (unsigned i = 0, e = msg->getNumArgs(); i != e; ++i)
if (Expr *capturer = findCapturingExpr(*this, msg->getArg(i), owner))
return diagnoseRetainCycle(*this, capturer, owner);
}
/// Check a property assign to see if it's likely to cause a retain cycle.
void Sema::checkRetainCycles(Expr *receiver, Expr *argument) {
RetainCycleOwner owner;
if (!findRetainCycleOwner(receiver, owner))
return;
if (Expr *capturer = findCapturingExpr(*this, argument, owner))
diagnoseRetainCycle(*this, capturer, owner);
}
void Sema::checkUnsafeAssigns(SourceLocation Loc,
QualType LHS, Expr *RHS) {
Qualifiers::ObjCLifetime LT = LHS.getObjCLifetime();
if (LT != Qualifiers::OCL_Weak && LT != Qualifiers::OCL_ExplicitNone)
return;
if (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS))
if (cast->getCastKind() == CK_ObjCConsumeObject)
Diag(Loc, diag::warn_arc_retained_assign)
<< (LT == Qualifiers::OCL_ExplicitNone)
<< RHS->getSourceRange();
}

Some files were not shown because too many files have changed in this diff Show More