This called a build failure:<div><br></div><div><a href="http://bb.pgr.jp/builders/cmake-clang-x86_64-linux/builds/5542/steps/build_clang/logs/stdio">http://bb.pgr.jp/builders/cmake-clang-x86_64-linux/builds/5542/steps/build_clang/logs/stdio</a></div>
<div><br><div class="gmail_quote">On Sun, Nov 6, 2011 at 1:01 AM, John McCall <span dir="ltr"><<a href="mailto:rjmccall@apple.com">rjmccall@apple.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
Author: rjmccall<br>
Date: Sun Nov 6 03:01:30 2011<br>
New Revision: 143867<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=143867&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=143867&view=rev</a><br>
Log:<br>
Change the AST representation of operations on Objective-C<br>
property references to use a new PseudoObjectExpr<br>
expression which pairs a syntactic form of the expression<br>
with a set of semantic expressions implementing it.<br>
This should significantly reduce the complexity required<br>
elsewhere in the compiler to deal with these kinds of<br>
expressions (e.g. IR generation's special l-value kind,<br>
the static analyzer's Message abstraction), at the lower<br>
cost of specifically dealing with the odd AST structure<br>
of these expressions. It should also greatly simplify<br>
efforts to implement similar language features in the<br>
future, most notably Managed C++'s properties and indexed<br>
properties.<br>
<br>
Most of the effort here is in dealing with the various<br>
clients of the AST. I've gone ahead and simplified the<br>
ObjC rewriter's use of properties; other clients, like<br>
IR-gen and the static analyzer, have all the old<br>
complexity *and* all the new complexity, at least<br>
temporarily. Many thanks to Ted for writing and advising<br>
on the necessary changes to the static analyzer.<br>
<br>
I've xfailed a small diagnostics regression in the static<br>
analyzer at Ted's request.<br>
<br>
<br>
Modified:<br>
cfe/trunk/include/clang/AST/DeclBase.h<br>
cfe/trunk/include/clang/AST/Expr.h<br>
cfe/trunk/include/clang/AST/RecursiveASTVisitor.h<br>
cfe/trunk/include/clang/AST/Stmt.h<br>
cfe/trunk/include/clang/Basic/StmtNodes.td<br>
cfe/trunk/include/clang/Serialization/ASTBitCodes.h<br>
cfe/trunk/lib/ARCMigrate/TransRetainReleaseDealloc.cpp<br>
cfe/trunk/lib/ARCMigrate/TransUnbridgedCasts.cpp<br>
cfe/trunk/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp<br>
cfe/trunk/lib/AST/DeclBase.cpp<br>
cfe/trunk/lib/AST/Expr.cpp<br>
cfe/trunk/lib/AST/ExprClassification.cpp<br>
cfe/trunk/lib/AST/ExprConstant.cpp<br>
cfe/trunk/lib/AST/ItaniumMangle.cpp<br>
cfe/trunk/lib/AST/StmtDumper.cpp<br>
cfe/trunk/lib/AST/StmtPrinter.cpp<br>
cfe/trunk/lib/AST/StmtProfile.cpp<br>
cfe/trunk/lib/Analysis/CFG.cpp<br>
cfe/trunk/lib/Analysis/LiveVariables.cpp<br>
cfe/trunk/lib/CodeGen/CGExpr.cpp<br>
cfe/trunk/lib/CodeGen/CGExprAgg.cpp<br>
cfe/trunk/lib/CodeGen/CGExprComplex.cpp<br>
cfe/trunk/lib/CodeGen/CGExprScalar.cpp<br>
cfe/trunk/lib/CodeGen/CGObjC.cpp<br>
cfe/trunk/lib/CodeGen/CGValue.h<br>
cfe/trunk/lib/CodeGen/CodeGenFunction.h<br>
cfe/trunk/lib/Rewrite/RewriteObjC.cpp<br>
cfe/trunk/lib/Sema/SemaChecking.cpp<br>
cfe/trunk/lib/Sema/SemaExpr.cpp<br>
cfe/trunk/lib/Sema/SemaExprObjC.cpp<br>
cfe/trunk/lib/Sema/SemaPseudoObject.cpp<br>
cfe/trunk/lib/Sema/SemaStmt.cpp<br>
cfe/trunk/lib/Sema/TreeTransform.h<br>
cfe/trunk/lib/Serialization/ASTReaderStmt.cpp<br>
cfe/trunk/lib/Serialization/ASTWriterStmt.cpp<br>
cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp<br>
cfe/trunk/test/Analysis/casts.m<br>
cfe/trunk/test/Analysis/retain-release-path-notes.m<br>
cfe/trunk/tools/libclang/CIndex.cpp<br>
cfe/trunk/tools/libclang/CXCursor.cpp<br>
<br>
Modified: cfe/trunk/include/clang/AST/DeclBase.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/AST/DeclBase.h (original)<br>
+++ cfe/trunk/include/clang/AST/DeclBase.h Sun Nov 6 03:01:30 2011<br>
@@ -974,6 +974,14 @@<br>
/// declaration context DC.<br>
bool Encloses(const DeclContext *DC) const;<br>
<br>
+ /// \brief Find the nearest non-closure ancestor of this context,<br>
+ /// i.e. the innermost semantic parent of this context which is not<br>
+ /// a closure. A context may be its own non-closure ancestor.<br>
+ DeclContext *getNonClosureAncestor();<br>
+ const DeclContext *getNonClosureAncestor() const {<br>
+ return const_cast<DeclContext*>(this)->getNonClosureAncestor();<br>
+ }<br>
+<br>
/// getPrimaryContext - There may be many different<br>
/// declarations of the same entity (including forward declarations<br>
/// of classes, multiple definitions of namespaces, etc.), each with<br>
<br>
Modified: cfe/trunk/include/clang/AST/Expr.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/AST/Expr.h (original)<br>
+++ cfe/trunk/include/clang/AST/Expr.h Sun Nov 6 03:01:30 2011<br>
@@ -2758,6 +2758,13 @@<br>
bool isCompoundAssignmentOp() const {<br>
return isCompoundAssignmentOp(getOpcode());<br>
}<br>
+ static Opcode getOpForCompoundAssignment(Opcode Opc) {<br>
+ assert(isCompoundAssignmentOp(Opc));<br>
+ if (Opc >= BO_XorAssign)<br>
+ return Opcode(unsigned(Opc) - BO_XorAssign + BO_Xor);<br>
+ else<br>
+ return Opcode(unsigned(Opc) - BO_MulAssign + BO_Mul);<br>
+ }<br>
<br>
static bool isShiftAssignOp(Opcode Opc) {<br>
return Opc == BO_ShlAssign || Opc == BO_ShrAssign;<br>
@@ -4251,6 +4258,140 @@<br>
child_range children() { return child_range(&SrcExpr, &SrcExpr+1); }<br>
};<br>
<br>
+/// PseudoObjectExpr - An expression which accesses a pseudo-object<br>
+/// l-value. A pseudo-object is an abstract object, accesses to which<br>
+/// are translated to calls. The pseudo-object expression has a<br>
+/// syntactic form, which shows how the expression was actually<br>
+/// written in the source code, and a semantic form, which is a series<br>
+/// of expressions to be executed in order which detail how the<br>
+/// operation is actually evaluated. Optionally, one of the semantic<br>
+/// forms may also provide a result value for the expression.<br>
+///<br>
+/// If any of the semantic-form expressions is an OpaqueValueExpr,<br>
+/// that OVE is required to have a source expression, and it is bound<br>
+/// to the result of that source expression. Such OVEs may appear<br>
+/// only in subsequent semantic-form expressions and as<br>
+/// sub-expressions of the syntactic form.<br>
+///<br>
+/// PseudoObjectExpr should be used only when an operation can be<br>
+/// usefully described in terms of fairly simple rewrite rules on<br>
+/// objects and functions that are meant to be used by end-developers.<br>
+/// For example, under the Itanium ABI, dynamic casts are implemented<br>
+/// as a call to a runtime function called __dynamic_cast; using this<br>
+/// class to describe that would be inappropriate because that call is<br>
+/// not really part of the user-visible semantics, and instead the<br>
+/// cast is properly reflected in the AST and IR-generation has been<br>
+/// taught to generate the call as necessary. In contrast, an<br>
+/// Objective-C property access is semantically defined to be<br>
+/// equivalent to a particular message send, and this is very much<br>
+/// part of the user model. The name of this class encourages this<br>
+/// modelling design.<br>
+class PseudoObjectExpr : public Expr {<br>
+ // PseudoObjectExprBits.NumSubExprs - The number of sub-expressions.<br>
+ // Always at least two, because the first sub-expression is the<br>
+ // syntactic form.<br>
+<br>
+ // PseudoObjectExprBits.ResultIndex - The index of the<br>
+ // sub-expression holding the result. 0 means the result is void,<br>
+ // which is unambiguous because it's the index of the syntactic<br>
+ // form. Note that this is therefore 1 higher than the value passed<br>
+ // in to Create, which is an index within the semantic forms.<br>
+ // Note also that ASTStmtWriter assumes this encoding.<br>
+<br>
+ Expr **getSubExprsBuffer() { return reinterpret_cast<Expr**>(this + 1); }<br>
+ const Expr * const *getSubExprsBuffer() const {<br>
+ return reinterpret_cast<const Expr * const *>(this + 1);<br>
+ }<br>
+<br>
+ friend class ASTStmtReader;<br>
+<br>
+ PseudoObjectExpr(QualType type, ExprValueKind VK,<br>
+ Expr *syntactic, ArrayRef<Expr*> semantic,<br>
+ unsigned resultIndex);<br>
+<br>
+ PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs);<br>
+<br>
+ unsigned getNumSubExprs() const {<br>
+ return PseudoObjectExprBits.NumSubExprs;<br>
+ }<br>
+<br>
+public:<br>
+ /// NoResult - A value for the result index indicating that there is<br>
+ /// no semantic result.<br>
+ enum { NoResult = ~0U };<br>
+<br>
+ static PseudoObjectExpr *Create(ASTContext &Context, Expr *syntactic,<br>
+ ArrayRef<Expr*> semantic,<br>
+ unsigned resultIndex);<br>
+<br>
+ static PseudoObjectExpr *Create(ASTContext &Context, EmptyShell shell,<br>
+ unsigned numSemanticExprs);<br>
+<br>
+ /// Return the syntactic form of this expression, i.e. the<br>
+ /// expression it actually looks like. Likely to be expressed in<br>
+ /// terms of OpaqueValueExprs bound in the semantic form.<br>
+ Expr *getSyntacticForm() { return getSubExprsBuffer()[0]; }<br>
+ const Expr *getSyntacticForm() const { return getSubExprsBuffer()[0]; }<br>
+<br>
+ /// Return the index of the result-bearing expression into the semantics<br>
+ /// expressions, or PseudoObjectExpr::NoResult if there is none.<br>
+ unsigned getResultExprIndex() const {<br>
+ if (PseudoObjectExprBits.ResultIndex == 0) return NoResult;<br>
+ return PseudoObjectExprBits.ResultIndex - 1;<br>
+ }<br>
+<br>
+ /// Return the result-bearing expression, or null if there is none.<br>
+ Expr *getResultExpr() {<br>
+ if (PseudoObjectExprBits.ResultIndex == 0)<br>
+ return 0;<br>
+ return getSubExprsBuffer()[PseudoObjectExprBits.ResultIndex];<br>
+ }<br>
+ const Expr *getResultExpr() const {<br>
+ return const_cast<PseudoObjectExpr*>(this)->getResultExpr();<br>
+ }<br>
+<br>
+ unsigned getNumSemanticExprs() const { return getNumSubExprs() - 1; }<br>
+<br>
+ typedef Expr * const *semantics_iterator;<br>
+ typedef const Expr * const *const_semantics_iterator;<br>
+ semantics_iterator semantics_begin() {<br>
+ return getSubExprsBuffer() + 1;<br>
+ }<br>
+ const_semantics_iterator semantics_begin() const {<br>
+ return getSubExprsBuffer() + 1;<br>
+ }<br>
+ semantics_iterator semantics_end() {<br>
+ return getSubExprsBuffer() + getNumSubExprs();<br>
+ }<br>
+ const_semantics_iterator semantics_end() const {<br>
+ return getSubExprsBuffer() + getNumSubExprs();<br>
+ }<br>
+ Expr *getSemanticExpr(unsigned index) {<br>
+ assert(index + 1 < getNumSubExprs());<br>
+ return getSubExprsBuffer()[index + 1];<br>
+ }<br>
+ const Expr *getSemanticExpr(unsigned index) const {<br>
+ return const_cast<PseudoObjectExpr*>(this)->getSemanticExpr(index);<br>
+ }<br>
+<br>
+ SourceLocation getExprLoc() const {<br>
+ return getSyntacticForm()->getExprLoc();<br>
+ }<br>
+ SourceRange getSourceRange() const {<br>
+ return getSyntacticForm()->getSourceRange();<br>
+ }<br>
+<br>
+ child_range children() {<br>
+ Stmt **cs = reinterpret_cast<Stmt**>(getSubExprsBuffer());<br>
+ return child_range(cs, cs + getNumSubExprs());<br>
+ }<br>
+<br>
+ static bool classof(const Stmt *T) {<br>
+ return T->getStmtClass() == PseudoObjectExprClass;<br>
+ }<br>
+ static bool classof(const PseudoObjectExpr *) { return true; }<br>
+};<br>
+<br>
/// AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*,<br>
/// __atomic_load, __atomic_store, and __atomic_compare_exchange_*, for the<br>
/// similarly-named C++0x instructions. All of these instructions take one<br>
<br>
Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original)<br>
+++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Sun Nov 6 03:01:30 2011<br>
@@ -1874,6 +1874,23 @@<br>
return true;<br>
}<br>
<br>
+// PseudoObjectExpr is a special case because of the wierdness with<br>
+// syntactic expressions and opaque values.<br>
+template<typename Derived><br>
+bool RecursiveASTVisitor<Derived>::<br>
+TraversePseudoObjectExpr(PseudoObjectExpr *S) {<br>
+ TRY_TO(WalkUpFromPseudoObjectExpr(S));<br>
+ TRY_TO(TraverseStmt(S->getSyntacticForm()));<br>
+ for (PseudoObjectExpr::semantics_iterator<br>
+ i = S->semantics_begin(), e = S->semantics_end(); i != e; ++i) {<br>
+ Expr *sub = *i;<br>
+ if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(sub))<br>
+ sub = OVE->getSourceExpr();<br>
+ TRY_TO(TraverseStmt(sub));<br>
+ }<br>
+ return true;<br>
+}<br>
+<br>
DEF_TRAVERSE_STMT(CXXScalarValueInitExpr, {<br>
// This is called for code like 'return T()' where T is a built-in<br>
// (i.e. non-class) type.<br>
<br>
Modified: cfe/trunk/include/clang/AST/Stmt.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Stmt.h?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Stmt.h?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/AST/Stmt.h (original)<br>
+++ cfe/trunk/include/clang/AST/Stmt.h Sun Nov 6 03:01:30 2011<br>
@@ -146,6 +146,7 @@<br>
friend class CXXUnresolvedConstructExpr; // ctor<br>
friend class CXXDependentScopeMemberExpr; // ctor<br>
friend class OverloadExpr; // ctor<br>
+ friend class PseudoObjectExpr; // ctor<br>
friend class AtomicExpr; // ctor<br>
unsigned : NumStmtBits;<br>
<br>
@@ -184,6 +185,18 @@<br>
unsigned NumPreArgs : 1;<br>
};<br>
<br>
+ class PseudoObjectExprBitfields {<br>
+ friend class PseudoObjectExpr;<br>
+ friend class ASTStmtReader; // deserialization<br>
+<br>
+ unsigned : NumExprBits;<br>
+<br>
+ // These don't need to be particularly wide, because they're<br>
+ // strictly limited by the forms of expressions we permit.<br>
+ unsigned NumSubExprs : 8;<br>
+ unsigned ResultIndex : 32 - 8 - NumExprBits;<br>
+ };<br>
+<br>
class ObjCIndirectCopyRestoreExprBitfields {<br>
friend class ObjCIndirectCopyRestoreExpr;<br>
unsigned : NumExprBits;<br>
@@ -201,6 +214,7 @@<br>
DeclRefExprBitfields DeclRefExprBits;<br>
CastExprBitfields CastExprBits;<br>
CallExprBitfields CallExprBits;<br>
+ PseudoObjectExprBitfields PseudoObjectExprBits;<br>
ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits;<br>
};<br>
<br>
<br>
Modified: cfe/trunk/include/clang/Basic/StmtNodes.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/StmtNodes.td?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/StmtNodes.td?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/StmtNodes.td (original)<br>
+++ cfe/trunk/include/clang/Basic/StmtNodes.td Sun Nov 6 03:01:30 2011<br>
@@ -77,6 +77,7 @@<br>
def ParenListExpr : DStmt<Expr>;<br>
def VAArgExpr : DStmt<Expr>;<br>
def GenericSelectionExpr : DStmt<Expr>;<br>
+def PseudoObjectExpr : DStmt<Expr>;<br>
<br>
// Atomic expressions<br>
def AtomicExpr : DStmt<Expr>;<br>
<br>
Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)<br>
+++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Sun Nov 6 03:01:30 2011<br>
@@ -1000,6 +1000,8 @@<br>
EXPR_BLOCK_DECL_REF,<br>
/// \brief A GenericSelectionExpr record.<br>
EXPR_GENERIC_SELECTION,<br>
+ /// \brief A PseudoObjectExpr record.<br>
+ EXPR_PSEUDO_OBJECT,<br>
/// \brief An AtomicExpr record.<br>
EXPR_ATOMIC,<br>
<br>
<br>
Modified: cfe/trunk/lib/ARCMigrate/TransRetainReleaseDealloc.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/TransRetainReleaseDealloc.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/TransRetainReleaseDealloc.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/ARCMigrate/TransRetainReleaseDealloc.cpp (original)<br>
+++ cfe/trunk/lib/ARCMigrate/TransRetainReleaseDealloc.cpp Sun Nov 6 03:01:30 2011<br>
@@ -160,12 +160,14 @@<br>
if (!E) return false;<br>
<br>
E = E->IgnoreParenCasts();<br>
+<br>
+ // Also look through property-getter sugar.<br>
+ if (PseudoObjectExpr *pseudoOp = dyn_cast<PseudoObjectExpr>(E))<br>
+ E = pseudoOp->getResultExpr()->IgnoreImplicit();<br>
+<br>
if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))<br>
return (ME->isInstanceMessage() && ME->getSelector() == DelegateSel);<br>
<br>
- if (ObjCPropertyRefExpr *propE = dyn_cast<ObjCPropertyRefExpr>(E))<br>
- return propE->getGetterSelector() == DelegateSel;<br>
-<br>
return false;<br>
}<br>
<br>
<br>
Modified: cfe/trunk/lib/ARCMigrate/TransUnbridgedCasts.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/TransUnbridgedCasts.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/TransUnbridgedCasts.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/ARCMigrate/TransUnbridgedCasts.cpp (original)<br>
+++ cfe/trunk/lib/ARCMigrate/TransUnbridgedCasts.cpp Sun Nov 6 03:01:30 2011<br>
@@ -236,7 +236,15 @@<br>
}<br>
}<br>
<br>
- if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getSubExpr())){<br>
+ Expr *subExpr = E->getSubExpr();<br>
+<br>
+ // Look through pseudo-object expressions.<br>
+ if (PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(subExpr)) {<br>
+ subExpr = pseudo->getResultExpr();<br>
+ assert(subExpr && "no result for pseudo-object of non-void type?");<br>
+ }<br>
+<br>
+ if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(subExpr)) {<br>
if (implCE->getCastKind() == CK_ARCConsumeObject)<br>
return rewriteToBridgedCast(E, OBC_BridgeRetained);<br>
if (implCE->getCastKind() == CK_ARCReclaimReturnedObject)<br>
<br>
Modified: cfe/trunk/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp (original)<br>
+++ cfe/trunk/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp Sun Nov 6 03:01:30 2011<br>
@@ -78,6 +78,15 @@<br>
return true;<br>
}<br>
<br>
+ bool VisitPseudoObjectExpr(PseudoObjectExpr *POE) {<br>
+ if (isZeroingPropIvar(POE) && isRemovable(POE)) {<br>
+ Transaction Trans(Pass.TA);<br>
+ Pass.TA.removeStmt(POE);<br>
+ }<br>
+<br>
+ return true;<br>
+ }<br>
+<br>
bool VisitBinaryOperator(BinaryOperator *BOE) {<br>
if (isZeroingPropIvar(BOE) && isRemovable(BOE)) {<br>
Transaction Trans(Pass.TA);<br>
@@ -142,17 +151,21 @@<br>
}<br>
<br>
bool isZeroingPropIvar(Expr *E) {<br>
- BinaryOperator *BOE = dyn_cast_or_null<BinaryOperator>(E);<br>
- if (!BOE) return false;<br>
+ E = E->IgnoreParens();<br>
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E))<br>
+ return isZeroingPropIvar(BO);<br>
+ if (PseudoObjectExpr *PO = dyn_cast<PseudoObjectExpr>(E))<br>
+ return isZeroingPropIvar(PO);<br>
+ return false;<br>
+ }<br>
<br>
+ bool isZeroingPropIvar(BinaryOperator *BOE) {<br>
if (BOE->getOpcode() == BO_Comma)<br>
return isZeroingPropIvar(BOE->getLHS()) &&<br>
isZeroingPropIvar(BOE->getRHS());<br>
<br>
if (BOE->getOpcode() != BO_Assign)<br>
- return false;<br>
-<br>
- ASTContext &Ctx = Pass.Ctx;<br>
+ return false;<br>
<br>
Expr *LHS = BOE->getLHS();<br>
if (ObjCIvarRefExpr *IV = dyn_cast<ObjCIvarRefExpr>(LHS)) {<br>
@@ -172,25 +185,38 @@<br>
if (!IvarBacksPropertySynthesis)<br>
return false;<br>
}<br>
- else if (ObjCPropertyRefExpr *PropRefExp = dyn_cast<ObjCPropertyRefExpr>(LHS)) {<br>
- // TODO: Using implicit property decl.<br>
- if (PropRefExp->isImplicitProperty())<br>
- return false;<br>
- if (ObjCPropertyDecl *PDecl = PropRefExp->getExplicitProperty()) {<br>
- if (!SynthesizedProperties.count(PDecl))<br>
- return false;<br>
- }<br>
- }<br>
else<br>
return false;<br>
<br>
- Expr *RHS = BOE->getRHS();<br>
- bool RHSIsNull = RHS->isNullPointerConstant(Ctx,<br>
- Expr::NPC_ValueDependentIsNull);<br>
- if (RHSIsNull)<br>
+ return isZero(BOE->getRHS());<br>
+ }<br>
+<br>
+ bool isZeroingPropIvar(PseudoObjectExpr *PO) {<br>
+ BinaryOperator *BO = dyn_cast<BinaryOperator>(PO->getSyntacticForm());<br>
+ if (!BO) return false;<br>
+ if (BO->getOpcode() != BO_Assign) return false;<br>
+<br>
+ ObjCPropertyRefExpr *PropRefExp =<br>
+ dyn_cast<ObjCPropertyRefExpr>(BO->getLHS()->IgnoreParens());<br>
+ if (!PropRefExp) return false;<br>
+<br>
+ // TODO: Using implicit property decl.<br>
+ if (PropRefExp->isImplicitProperty())<br>
+ return false;<br>
+<br>
+ if (ObjCPropertyDecl *PDecl = PropRefExp->getExplicitProperty()) {<br>
+ if (!SynthesizedProperties.count(PDecl))<br>
+ return false;<br>
+ }<br>
+<br>
+ return isZero(cast<OpaqueValueExpr>(BO->getRHS())->getSourceExpr());<br>
+ }<br>
+<br>
+ bool isZero(Expr *E) {<br>
+ if (E->isNullPointerConstant(Pass.Ctx, Expr::NPC_ValueDependentIsNull))<br>
return true;<br>
<br>
- return isZeroingPropIvar(RHS);<br>
+ return isZeroingPropIvar(E);<br>
}<br>
};<br>
<br>
<br>
Modified: cfe/trunk/lib/AST/DeclBase.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/DeclBase.cpp (original)<br>
+++ cfe/trunk/lib/AST/DeclBase.cpp Sun Nov 6 03:01:30 2011<br>
@@ -640,7 +640,11 @@<br>
}<br>
<br>
DeclContext *Decl::getNonClosureContext() {<br>
- DeclContext *DC = getDeclContext();<br>
+ return getDeclContext()->getNonClosureAncestor();<br>
+}<br>
+<br>
+DeclContext *DeclContext::getNonClosureAncestor() {<br>
+ DeclContext *DC = this;<br>
<br>
// This is basically "while (DC->isClosure()) DC = DC->getParent();"<br>
// except that it's significantly more efficient to cast to a known<br>
<br>
Modified: cfe/trunk/lib/AST/Expr.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/Expr.cpp (original)<br>
+++ cfe/trunk/lib/AST/Expr.cpp Sun Nov 6 03:01:30 2011<br>
@@ -1694,6 +1694,19 @@<br>
R1 = getSourceRange();<br>
return true;<br>
<br>
+ case PseudoObjectExprClass: {<br>
+ const PseudoObjectExpr *PO = cast<PseudoObjectExpr>(this);<br>
+<br>
+ // Only complain about things that have the form of a getter.<br>
+ if (isa<UnaryOperator>(PO->getSyntacticForm()) ||<br>
+ isa<BinaryOperator>(PO->getSyntacticForm()))<br>
+ return false;<br>
+<br>
+ Loc = getExprLoc();<br>
+ R1 = getSourceRange();<br>
+ return true;<br>
+ }<br>
+<br>
case StmtExprClass: {<br>
// Statement exprs don't logically have side effects themselves, but are<br>
// sometimes used in macros in ways that give them a type that is unused.<br>
@@ -2598,6 +2611,9 @@<br>
} else if (const MaterializeTemporaryExpr *M<br>
= dyn_cast<MaterializeTemporaryExpr>(this)) {<br>
return M->GetTemporaryExpr()->isNullPointerConstant(Ctx, NPC);<br>
+ } else if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(this)) {<br>
+ if (const Expr *Source = OVE->getSourceExpr())<br>
+ return Source->isNullPointerConstant(Ctx, NPC);<br>
}<br>
<br>
// C++0x nullptr_t is always a null pointer constant.<br>
@@ -3306,6 +3322,72 @@<br>
return cast<OpaqueValueExpr>(e);<br>
}<br>
<br>
+PseudoObjectExpr *PseudoObjectExpr::Create(ASTContext &Context, EmptyShell sh,<br>
+ unsigned numSemanticExprs) {<br>
+ void *buffer = Context.Allocate(sizeof(PseudoObjectExpr) +<br>
+ (1 + numSemanticExprs) * sizeof(Expr*),<br>
+ llvm::alignOf<PseudoObjectExpr>());<br>
+ return new(buffer) PseudoObjectExpr(sh, numSemanticExprs);<br>
+}<br>
+<br>
+PseudoObjectExpr::PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs)<br>
+ : Expr(PseudoObjectExprClass, shell) {<br>
+ PseudoObjectExprBits.NumSubExprs = numSemanticExprs + 1;<br>
+}<br>
+<br>
+PseudoObjectExpr *PseudoObjectExpr::Create(ASTContext &C, Expr *syntax,<br>
+ ArrayRef<Expr*> semantics,<br>
+ unsigned resultIndex) {<br>
+ assert(syntax && "no syntactic expression!");<br>
+ assert(semantics.size() && "no semantic expressions!");<br>
+<br>
+ QualType type;<br>
+ ExprValueKind VK;<br>
+ if (resultIndex == NoResult) {<br>
+ type = C.VoidTy;<br>
+ VK = VK_RValue;<br>
+ } else {<br>
+ assert(resultIndex < semantics.size());<br>
+ type = semantics[resultIndex]->getType();<br>
+ VK = semantics[resultIndex]->getValueKind();<br>
+ assert(semantics[resultIndex]->getObjectKind() == OK_Ordinary);<br>
+ }<br>
+<br>
+ void *buffer = C.Allocate(sizeof(PseudoObjectExpr) +<br>
+ (1 + semantics.size()) * sizeof(Expr*),<br>
+ llvm::alignOf<PseudoObjectExpr>());<br>
+ return new(buffer) PseudoObjectExpr(type, VK, syntax, semantics,<br>
+ resultIndex);<br>
+}<br>
+<br>
+PseudoObjectExpr::PseudoObjectExpr(QualType type, ExprValueKind VK,<br>
+ Expr *syntax, ArrayRef<Expr*> semantics,<br>
+ unsigned resultIndex)<br>
+ : Expr(PseudoObjectExprClass, type, VK, OK_Ordinary,<br>
+ /*filled in at end of ctor*/ false, false, false, false) {<br>
+ PseudoObjectExprBits.NumSubExprs = semantics.size() + 1;<br>
+ PseudoObjectExprBits.ResultIndex = resultIndex + 1;<br>
+<br>
+ for (unsigned i = 0, e = semantics.size() + 1; i != e; ++i) {<br>
+ Expr *E = (i == 0 ? syntax : semantics[i-1]);<br>
+ getSubExprsBuffer()[i] = E;<br>
+<br>
+ if (E->isTypeDependent())<br>
+ ExprBits.TypeDependent = true;<br>
+ if (E->isValueDependent())<br>
+ ExprBits.ValueDependent = true;<br>
+ if (E->isInstantiationDependent())<br>
+ ExprBits.InstantiationDependent = true;<br>
+ if (E->containsUnexpandedParameterPack())<br>
+ ExprBits.ContainsUnexpandedParameterPack = true;<br>
+<br>
+ if (isa<OpaqueValueExpr>(E))<br>
+ assert(cast<OpaqueValueExpr>(E)->getSourceExpr() != 0 &&<br>
+ "opaque-value semantic expressions for pseudo-object "<br>
+ "operations must have sources");<br>
+ }<br>
+}<br>
+<br>
//===----------------------------------------------------------------------===//<br>
// ExprIterator.<br>
//===----------------------------------------------------------------------===//<br>
<br>
Modified: cfe/trunk/lib/AST/ExprClassification.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprClassification.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprClassification.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/ExprClassification.cpp (original)<br>
+++ cfe/trunk/lib/AST/ExprClassification.cpp Sun Nov 6 03:01:30 2011<br>
@@ -232,6 +232,11 @@<br>
return ClassifyExprValueKind(Lang, E,<br>
cast<OpaqueValueExpr>(E)->getValueKind());<br>
<br>
+ // Pseudo-object expressions can produce l-values with reference magic.<br>
+ case Expr::PseudoObjectExprClass:<br>
+ return ClassifyExprValueKind(Lang, E,<br>
+ cast<PseudoObjectExpr>(E)->getValueKind());<br>
+<br>
// Implicit casts are lvalues if they're lvalue casts. Other than that, we<br>
// only specifically record class temporaries.<br>
case Expr::ImplicitCastExprClass:<br>
<br>
Modified: cfe/trunk/lib/AST/ExprConstant.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)<br>
+++ cfe/trunk/lib/AST/ExprConstant.cpp Sun Nov 6 03:01:30 2011<br>
@@ -3450,6 +3450,7 @@<br>
case Expr::AsTypeExprClass:<br>
case Expr::ObjCIndirectCopyRestoreExprClass:<br>
case Expr::MaterializeTemporaryExprClass:<br>
+ case Expr::PseudoObjectExprClass:<br>
case Expr::AtomicExprClass:<br>
return ICEDiag(2, E->getLocStart());<br>
<br>
<br>
Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/ItaniumMangle.cpp (original)<br>
+++ cfe/trunk/lib/AST/ItaniumMangle.cpp Sun Nov 6 03:01:30 2011<br>
@@ -2257,6 +2257,7 @@<br>
case Expr::CXXNoexceptExprClass:<br>
case Expr::CUDAKernelCallExprClass:<br>
case Expr::AsTypeExprClass:<br>
+ case Expr::PseudoObjectExprClass:<br>
case Expr::AtomicExprClass:<br>
{<br>
// As bad as this diagnostic is, it's better than crashing.<br>
<br>
Modified: cfe/trunk/lib/AST/StmtDumper.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtDumper.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtDumper.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/StmtDumper.cpp (original)<br>
+++ cfe/trunk/lib/AST/StmtDumper.cpp Sun Nov 6 03:01:30 2011<br>
@@ -148,6 +148,7 @@<br>
void VisitCompoundAssignOperator(CompoundAssignOperator *Node);<br>
void VisitAddrLabelExpr(AddrLabelExpr *Node);<br>
void VisitBlockExpr(BlockExpr *Node);<br>
+ void VisitOpaqueValueExpr(OpaqueValueExpr *Node);<br>
<br>
// C++<br>
void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node);<br>
@@ -524,6 +525,15 @@<br>
DumpSubTree(block->getBody());<br>
}<br>
<br>
+void StmtDumper::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {<br>
+ DumpExpr(Node);<br>
+<br>
+ if (Expr *Source = Node->getSourceExpr()) {<br>
+ OS << '\n';<br>
+ DumpSubTree(Source);<br>
+ }<br>
+}<br>
+<br>
// GNU extensions.<br>
<br>
void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) {<br>
<br>
Modified: cfe/trunk/lib/AST/StmtPrinter.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)<br>
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Sun Nov 6 03:01:30 2011<br>
@@ -1027,6 +1027,10 @@<br>
OS << ")";<br>
}<br>
<br>
+void StmtPrinter::VisitPseudoObjectExpr(PseudoObjectExpr *Node) {<br>
+ PrintExpr(Node->getSyntacticForm());<br>
+}<br>
+<br>
void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) {<br>
const char *Name = 0;<br>
switch (Node->getOp()) {<br>
<br>
Modified: cfe/trunk/lib/AST/StmtProfile.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtProfile.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtProfile.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/StmtProfile.cpp (original)<br>
+++ cfe/trunk/lib/AST/StmtProfile.cpp Sun Nov 6 03:01:30 2011<br>
@@ -475,6 +475,15 @@<br>
}<br>
}<br>
<br>
+void StmtProfiler::VisitPseudoObjectExpr(const PseudoObjectExpr *S) {<br>
+ VisitExpr(S);<br>
+ for (PseudoObjectExpr::const_semantics_iterator<br>
+ i = S->semantics_begin(), e = S->semantics_end(); i != e; ++i)<br>
+ // Normally, we would not profile the source expressions of OVEs.<br>
+ if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(*i))<br>
+ Visit(OVE->getSourceExpr());<br>
+}<br>
+<br>
void StmtProfiler::VisitAtomicExpr(const AtomicExpr *S) {<br>
VisitExpr(S);<br>
ID.AddInteger(S->getOp());<br>
<br>
Modified: cfe/trunk/lib/Analysis/CFG.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Analysis/CFG.cpp (original)<br>
+++ cfe/trunk/lib/Analysis/CFG.cpp Sun Nov 6 03:01:30 2011<br>
@@ -344,6 +344,7 @@<br>
CFGBlock *VisitObjCAtTryStmt(ObjCAtTryStmt *S);<br>
CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S);<br>
CFGBlock *VisitReturnStmt(ReturnStmt *R);<br>
+ CFGBlock *VisitPseudoObjectExpr(PseudoObjectExpr *E);<br>
CFGBlock *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,<br>
AddStmtChoice asc);<br>
CFGBlock *VisitStmtExpr(StmtExpr *S, AddStmtChoice asc);<br>
@@ -981,6 +982,9 @@<br>
case Stmt::OpaqueValueExprClass:<br>
return Block;<br>
<br>
+ case Stmt::PseudoObjectExprClass:<br>
+ return VisitPseudoObjectExpr(cast<PseudoObjectExpr>(S));<br>
+<br>
case Stmt::ReturnStmtClass:<br>
return VisitReturnStmt(cast<ReturnStmt>(S));<br>
<br>
@@ -1907,6 +1911,31 @@<br>
return NYS();<br>
}<br>
<br>
+CFGBlock *CFGBuilder::VisitPseudoObjectExpr(PseudoObjectExpr *E) {<br>
+ autoCreateBlock();<br>
+<br>
+ // Add the PseudoObject as the last thing.<br>
+ appendStmt(Block, E);<br>
+<br>
+ CFGBlock *lastBlock = Block;<br>
+<br>
+ // Before that, evaluate all of the semantics in order. In<br>
+ // CFG-land, that means appending them in reverse order.<br>
+ for (unsigned i = E->getNumSemanticExprs(); i != 0; ) {<br>
+ Expr *Semantic = E->getSemanticExpr(--i);<br>
+<br>
+ // If the semantic is an opaque value, we're being asked to bind<br>
+ // it to its source expression.<br>
+ if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Semantic))<br>
+ Semantic = OVE->getSourceExpr();<br>
+<br>
+ if (CFGBlock *B = Visit(Semantic))<br>
+ lastBlock = B;<br>
+ }<br>
+<br>
+ return lastBlock;<br>
+}<br>
+<br>
CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {<br>
CFGBlock *LoopSuccessor = NULL;<br>
<br>
<br>
Modified: cfe/trunk/lib/Analysis/LiveVariables.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/LiveVariables.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/LiveVariables.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Analysis/LiveVariables.cpp (original)<br>
+++ cfe/trunk/lib/Analysis/LiveVariables.cpp Sun Nov 6 03:01:30 2011<br>
@@ -288,6 +288,18 @@<br>
}<br>
break;<br>
}<br>
+ case Stmt::PseudoObjectExprClass: {<br>
+ // A pseudo-object operation only directly consumes its result<br>
+ // expression.<br>
+ Expr *child = cast<PseudoObjectExpr>(S)->getResultExpr();<br>
+ if (!child) return;<br>
+ if (OpaqueValueExpr *OV = dyn_cast<OpaqueValueExpr>(child))<br>
+ child = OV->getSourceExpr();<br>
+ child = child->IgnoreParens();<br>
+ val.liveStmts = LV.SSetFact.add(val.liveStmts, child);<br>
+ return;<br>
+ }<br>
+<br>
// FIXME: These cases eventually shouldn't be needed.<br>
case Stmt::ExprWithCleanupsClass: {<br>
S = cast<ExprWithCleanups>(S)->getSubExpr();<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Sun Nov 6 03:01:30 2011<br>
@@ -672,6 +672,8 @@<br>
return EmitStringLiteralLValue(cast<StringLiteral>(E));<br>
case Expr::ObjCEncodeExprClass:<br>
return EmitObjCEncodeExprLValue(cast<ObjCEncodeExpr>(E));<br>
+ case Expr::PseudoObjectExprClass:<br>
+ return EmitPseudoObjectLValue(cast<PseudoObjectExpr>(E));<br>
<br>
case Expr::BlockDeclRefExprClass:<br>
return EmitBlockDeclRefLValue(cast<BlockDeclRefExpr>(E));<br>
@@ -2768,3 +2770,86 @@<br>
cast<llvm::Instruction>(Val)->setMetadata(llvm::LLVMContext::MD_fpaccuracy,<br>
Node);<br>
}<br>
+<br>
+namespace {<br>
+ struct LValueOrRValue {<br>
+ LValue LV;<br>
+ RValue RV;<br>
+ };<br>
+}<br>
+<br>
+static LValueOrRValue emitPseudoObjectExpr(CodeGenFunction &CGF,<br>
+ const PseudoObjectExpr *E,<br>
+ bool forLValue,<br>
+ AggValueSlot slot) {<br>
+ llvm::SmallVector<CodeGenFunction::OpaqueValueMappingData, 4> opaques;<br>
+<br>
+ // Find the result expression, if any.<br>
+ const Expr *resultExpr = E->getResultExpr();<br>
+ LValueOrRValue result;<br>
+<br>
+ for (PseudoObjectExpr::const_semantics_iterator<br>
+ i = E->semantics_begin(), e = E->semantics_end(); i != e; ++i) {<br>
+ const Expr *semantic = *i;<br>
+<br>
+ // If this semantic expression is an opaque value, bind it<br>
+ // to the result of its source expression.<br>
+ if (const OpaqueValueExpr *ov = dyn_cast<OpaqueValueExpr>(semantic)) {<br>
+<br>
+ // If this is the result expression, we may need to evaluate<br>
+ // directly into the slot.<br>
+ typedef CodeGenFunction::OpaqueValueMappingData OVMA;<br>
+ OVMA opaqueData;<br>
+ if (ov == resultExpr && ov->isRValue() && !forLValue &&<br>
+ CodeGenFunction::hasAggregateLLVMType(ov->getType()) &&<br>
+ !ov->getType()->isAnyComplexType()) {<br>
+ CGF.EmitAggExpr(ov->getSourceExpr(), slot);<br>
+<br>
+ LValue LV = CGF.MakeAddrLValue(slot.getAddr(), ov->getType());<br>
+ opaqueData = OVMA::bind(CGF, ov, LV);<br>
+ result.RV = slot.asRValue();<br>
+<br>
+ // Otherwise, emit as normal.<br>
+ } else {<br>
+ opaqueData = OVMA::bind(CGF, ov, ov->getSourceExpr());<br>
+<br>
+ // If this is the result, also evaluate the result now.<br>
+ if (ov == resultExpr) {<br>
+ if (forLValue)<br>
+ result.LV = CGF.EmitLValue(ov);<br>
+ else<br>
+ result.RV = CGF.EmitAnyExpr(ov, slot);<br>
+ }<br>
+ }<br>
+<br>
+ opaques.push_back(opaqueData);<br>
+<br>
+ // Otherwise, if the expression is the result, evaluate it<br>
+ // and remember the result.<br>
+ } else if (semantic == resultExpr) {<br>
+ if (forLValue)<br>
+ result.LV = CGF.EmitLValue(semantic);<br>
+ else<br>
+ result.RV = CGF.EmitAnyExpr(semantic, slot);<br>
+<br>
+ // Otherwise, evaluate the expression in an ignored context.<br>
+ } else {<br>
+ CGF.EmitIgnoredExpr(semantic);<br>
+ }<br>
+ }<br>
+<br>
+ // Unbind all the opaques now.<br>
+ for (unsigned i = 0, e = opaques.size(); i != e; ++i)<br>
+ opaques[i].unbind(CGF);<br>
+<br>
+ return result;<br>
+}<br>
+<br>
+RValue CodeGenFunction::EmitPseudoObjectRValue(const PseudoObjectExpr *E,<br>
+ AggValueSlot slot) {<br>
+ return emitPseudoObjectExpr(*this, E, false, slot).RV;<br>
+}<br>
+<br>
+LValue CodeGenFunction::EmitPseudoObjectLValue(const PseudoObjectExpr *E) {<br>
+ return emitPseudoObjectExpr(*this, E, true, AggValueSlot::ignored()).LV;<br>
+}<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGExprAgg.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprAgg.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprAgg.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGExprAgg.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGExprAgg.cpp Sun Nov 6 03:01:30 2011<br>
@@ -148,6 +148,15 @@<br>
void VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E);<br>
void VisitOpaqueValueExpr(OpaqueValueExpr *E);<br>
<br>
+ void VisitPseudoObjectExpr(PseudoObjectExpr *E) {<br>
+ if (E->isGLValue()) {<br>
+ LValue LV = CGF.EmitPseudoObjectLValue(E);<br>
+ return EmitFinalDestCopy(E, LV);<br>
+ }<br>
+<br>
+ CGF.EmitPseudoObjectRValue(E, EnsureSlot(E->getType()));<br>
+ }<br>
+<br>
void VisitVAArgExpr(VAArgExpr *E);<br>
<br>
void EmitInitializationToLValue(Expr *E, LValue Address);<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGExprComplex.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprComplex.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprComplex.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGExprComplex.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGExprComplex.cpp Sun Nov 6 03:01:30 2011<br>
@@ -137,6 +137,10 @@<br>
return CGF.getOpaqueRValueMapping(E).getComplexVal();<br>
}<br>
<br>
+ ComplexPairTy VisitPseudoObjectExpr(PseudoObjectExpr *E) {<br>
+ return CGF.EmitPseudoObjectRValue(E).getComplexVal();<br>
+ }<br>
+<br>
// FIXME: CompoundLiteralExpr<br>
<br>
ComplexPairTy EmitCast(CastExpr::CastKind CK, Expr *Op, QualType DestTy);<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Sun Nov 6 03:01:30 2011<br>
@@ -197,6 +197,10 @@<br>
return llvm::ConstantInt::get(ConvertType(E->getType()),E->getPackLength());<br>
}<br>
<br>
+ Value *VisitPseudoObjectExpr(PseudoObjectExpr *E) {<br>
+ return CGF.EmitPseudoObjectRValue(E).getScalarVal();<br>
+ }<br>
+<br>
Value *VisitOpaqueValueExpr(OpaqueValueExpr *E) {<br>
if (E->isGLValue())<br>
return EmitLoadOfLValue(CGF.getOpaqueLValueMapping(E));<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGObjC.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjC.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjC.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGObjC.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGObjC.cpp Sun Nov 6 03:01:30 2011<br>
@@ -2231,6 +2231,59 @@<br>
return true;<br>
}<br>
<br>
+/// Try to emit a PseudoObjectExpr at +1.<br>
+///<br>
+/// This massively duplicates emitPseudoObjectRValue.<br>
+static TryEmitResult tryEmitARCRetainPseudoObject(CodeGenFunction &CGF,<br>
+ const PseudoObjectExpr *E) {<br>
+ llvm::SmallVector<CodeGenFunction::OpaqueValueMappingData, 4> opaques;<br>
+<br>
+ // Find the result expression.<br>
+ const Expr *resultExpr = E->getResultExpr();<br>
+ assert(resultExpr);<br>
+ TryEmitResult result;<br>
+<br>
+ for (PseudoObjectExpr::const_semantics_iterator<br>
+ i = E->semantics_begin(), e = E->semantics_end(); i != e; ++i) {<br>
+ const Expr *semantic = *i;<br>
+<br>
+ // If this semantic expression is an opaque value, bind it<br>
+ // to the result of its source expression.<br>
+ if (const OpaqueValueExpr *ov = dyn_cast<OpaqueValueExpr>(semantic)) {<br>
+ typedef CodeGenFunction::OpaqueValueMappingData OVMA;<br>
+ OVMA opaqueData;<br>
+<br>
+ // If this semantic is the result of the pseudo-object<br>
+ // expression, try to evaluate the source as +1.<br>
+ if (ov == resultExpr) {<br>
+ assert(!OVMA::shouldBindAsLValue(ov));<br>
+ result = tryEmitARCRetainScalarExpr(CGF, ov->getSourceExpr());<br>
+ opaqueData = OVMA::bind(CGF, ov, RValue::get(result.getPointer()));<br>
+<br>
+ // Otherwise, just bind it.<br>
+ } else {<br>
+ opaqueData = OVMA::bind(CGF, ov, ov->getSourceExpr());<br>
+ }<br>
+ opaques.push_back(opaqueData);<br>
+<br>
+ // Otherwise, if the expression is the result, evaluate it<br>
+ // and remember the result.<br>
+ } else if (semantic == resultExpr) {<br>
+ result = tryEmitARCRetainScalarExpr(CGF, semantic);<br>
+<br>
+ // Otherwise, evaluate the expression in an ignored context.<br>
+ } else {<br>
+ CGF.EmitIgnoredExpr(semantic);<br>
+ }<br>
+ }<br>
+<br>
+ // Unbind all the opaques now.<br>
+ for (unsigned i = 0, e = opaques.size(); i != e; ++i)<br>
+ opaques[i].unbind(CGF);<br>
+<br>
+ return result;<br>
+}<br>
+<br>
static TryEmitResult<br>
tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {<br>
// Look through cleanups.<br>
@@ -2356,6 +2409,17 @@<br>
llvm::Value *result = emitARCRetainCall(CGF, e);<br>
if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);<br>
return TryEmitResult(result, true);<br>
+<br>
+ // Look through pseudo-object expressions.<br>
+ } else if (const PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(e)) {<br>
+ TryEmitResult result<br>
+ = tryEmitARCRetainPseudoObject(CGF, pseudo);<br>
+ if (resultType) {<br>
+ llvm::Value *value = result.getPointer();<br>
+ value = CGF.Builder.CreateBitCast(value, resultType);<br>
+ result.setPointer(value);<br>
+ }<br>
+ return result;<br>
}<br>
<br>
// Conservatively halt the search at any other expression kind.<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGValue.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGValue.h?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGValue.h?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGValue.h (original)<br>
+++ cfe/trunk/lib/CodeGen/CGValue.h Sun Nov 6 03:01:30 2011<br>
@@ -27,6 +27,7 @@<br>
class ObjCPropertyRefExpr;<br>
<br>
namespace CodeGen {<br>
+ class AggValueSlot;<br>
class CGBitFieldInfo;<br>
<br>
/// RValue - This trivial value class is used to represent the result of an<br>
@@ -452,7 +453,7 @@<br>
RValue asRValue() const {<br>
return RValue::getAggregate(getAddr(), isVolatile());<br>
}<br>
-<br>
+<br>
void setZeroed(bool V = true) { ZeroedFlag = V; }<br>
IsZeroed_t isZeroed() const {<br>
return IsZeroed_t(ZeroedFlag);<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)<br>
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Sun Nov 6 03:01:30 2011<br>
@@ -950,20 +950,86 @@<br>
<br>
public:<br>
PeepholeProtection() : Inst(0) {}<br>
- };<br>
+ };<br>
<br>
- /// An RAII object to set (and then clear) a mapping for an OpaqueValueExpr.<br>
- class OpaqueValueMapping {<br>
- CodeGenFunction &CGF;<br>
+ /// A non-RAII class containing all the information about a bound<br>
+ /// opaque value. OpaqueValueMapping, below, is a RAII wrapper for<br>
+ /// this which makes individual mappings very simple; using this<br>
+ /// class directly is useful when you have a variable number of<br>
+ /// opaque values or don't want the RAII functionality for some<br>
+ /// reason.<br>
+ class OpaqueValueMappingData {<br>
const OpaqueValueExpr *OpaqueValue;<br>
bool BoundLValue;<br>
CodeGenFunction::PeepholeProtection Protection;<br>
<br>
+ OpaqueValueMappingData(const OpaqueValueExpr *ov,<br>
+ bool boundLValue)<br>
+ : OpaqueValue(ov), BoundLValue(boundLValue) {}<br>
public:<br>
+ OpaqueValueMappingData() : OpaqueValue(0) {}<br>
+<br>
static bool shouldBindAsLValue(const Expr *expr) {<br>
return expr->isGLValue() || expr->getType()->isRecordType();<br>
}<br>
<br>
+ static OpaqueValueMappingData bind(CodeGenFunction &CGF,<br>
+ const OpaqueValueExpr *ov,<br>
+ const Expr *e) {<br>
+ if (shouldBindAsLValue(ov))<br>
+ return bind(CGF, ov, CGF.EmitLValue(e));<br>
+ return bind(CGF, ov, CGF.EmitAnyExpr(e));<br>
+ }<br>
+<br>
+ static OpaqueValueMappingData bind(CodeGenFunction &CGF,<br>
+ const OpaqueValueExpr *ov,<br>
+ const LValue &lv) {<br>
+ assert(shouldBindAsLValue(ov));<br>
+ CGF.OpaqueLValues.insert(std::make_pair(ov, lv));<br>
+ return OpaqueValueMappingData(ov, true);<br>
+ }<br>
+<br>
+ static OpaqueValueMappingData bind(CodeGenFunction &CGF,<br>
+ const OpaqueValueExpr *ov,<br>
+ const RValue &rv) {<br>
+ assert(!shouldBindAsLValue(ov));<br>
+ CGF.OpaqueRValues.insert(std::make_pair(ov, rv));<br>
+<br>
+ OpaqueValueMappingData data(ov, false);<br>
+<br>
+ // Work around an extremely aggressive peephole optimization in<br>
+ // EmitScalarConversion which assumes that all other uses of a<br>
+ // value are extant.<br>
+ data.Protection = CGF.protectFromPeepholes(rv);<br>
+<br>
+ return data;<br>
+ }<br>
+<br>
+ bool isValid() const { return OpaqueValue != 0; }<br>
+ void clear() { OpaqueValue = 0; }<br>
+<br>
+ void unbind(CodeGenFunction &CGF) {<br>
+ assert(OpaqueValue && "no data to unbind!");<br>
+<br>
+ if (BoundLValue) {<br>
+ CGF.OpaqueLValues.erase(OpaqueValue);<br>
+ } else {<br>
+ CGF.OpaqueRValues.erase(OpaqueValue);<br>
+ CGF.unprotectFromPeepholes(Protection);<br>
+ }<br>
+ }<br>
+ };<br>
+<br>
+ /// An RAII object to set (and then clear) a mapping for an OpaqueValueExpr.<br>
+ class OpaqueValueMapping {<br>
+ CodeGenFunction &CGF;<br>
+ OpaqueValueMappingData Data;<br>
+<br>
+ public:<br>
+ static bool shouldBindAsLValue(const Expr *expr) {<br>
+ return OpaqueValueMappingData::shouldBindAsLValue(expr);<br>
+ }<br>
+<br>
/// Build the opaque value mapping for the given conditional<br>
/// operator if it's the GNU ?: extension. This is a common<br>
/// enough pattern that the convenience operator is really<br>
@@ -971,75 +1037,34 @@<br>
///<br>
OpaqueValueMapping(CodeGenFunction &CGF,<br>
const AbstractConditionalOperator *op) : CGF(CGF) {<br>
- if (isa<ConditionalOperator>(op)) {<br>
- OpaqueValue = 0;<br>
- BoundLValue = false;<br>
+ if (isa<ConditionalOperator>(op))<br>
+ // Leave Data empty.<br>
return;<br>
- }<br>
<br>
const BinaryConditionalOperator *e = cast<BinaryConditionalOperator>(op);<br>
- init(e->getOpaqueValue(), e->getCommon());<br>
+ Data = OpaqueValueMappingData::bind(CGF, e->getOpaqueValue(),<br>
+ e->getCommon());<br>
}<br>
<br>
OpaqueValueMapping(CodeGenFunction &CGF,<br>
const OpaqueValueExpr *opaqueValue,<br>
LValue lvalue)<br>
- : CGF(CGF), OpaqueValue(opaqueValue), BoundLValue(true) {<br>
- assert(opaqueValue && "no opaque value expression!");<br>
- assert(shouldBindAsLValue(opaqueValue));<br>
- initLValue(lvalue);<br>
+ : CGF(CGF), Data(OpaqueValueMappingData::bind(CGF, opaqueValue, lvalue)) {<br>
}<br>
<br>
OpaqueValueMapping(CodeGenFunction &CGF,<br>
const OpaqueValueExpr *opaqueValue,<br>
RValue rvalue)<br>
- : CGF(CGF), OpaqueValue(opaqueValue), BoundLValue(false) {<br>
- assert(opaqueValue && "no opaque value expression!");<br>
- assert(!shouldBindAsLValue(opaqueValue));<br>
- initRValue(rvalue);<br>
+ : CGF(CGF), Data(OpaqueValueMappingData::bind(CGF, opaqueValue, rvalue)) {<br>
}<br>
<br>
void pop() {<br>
- assert(OpaqueValue && "mapping already popped!");<br>
- popImpl();<br>
- OpaqueValue = 0;<br>
+ Data.unbind(CGF);<br>
+ Data.clear();<br>
}<br>
<br>
~OpaqueValueMapping() {<br>
- if (OpaqueValue) popImpl();<br>
- }<br>
-<br>
- private:<br>
- void popImpl() {<br>
- if (BoundLValue)<br>
- CGF.OpaqueLValues.erase(OpaqueValue);<br>
- else {<br>
- CGF.OpaqueRValues.erase(OpaqueValue);<br>
- CGF.unprotectFromPeepholes(Protection);<br>
- }<br>
- }<br>
-<br>
- void init(const OpaqueValueExpr *ov, const Expr *e) {<br>
- OpaqueValue = ov;<br>
- BoundLValue = shouldBindAsLValue(ov);<br>
- assert(BoundLValue == shouldBindAsLValue(e)<br>
- && "inconsistent expression value kinds!");<br>
- if (BoundLValue)<br>
- initLValue(CGF.EmitLValue(e));<br>
- else<br>
- initRValue(CGF.EmitAnyExpr(e));<br>
- }<br>
-<br>
- void initLValue(const LValue &lv) {<br>
- CGF.OpaqueLValues.insert(std::make_pair(OpaqueValue, lv));<br>
- }<br>
-<br>
- void initRValue(const RValue &rv) {<br>
- // Work around an extremely aggressive peephole optimization in<br>
- // EmitScalarConversion which assumes that all other uses of a<br>
- // value are extant.<br>
- Protection = CGF.protectFromPeepholes(rv);<br>
- CGF.OpaqueRValues.insert(std::make_pair(OpaqueValue, rv));<br>
+ if (Data.isValid()) Data.unbind(CGF);<br>
}<br>
};<br>
<br>
@@ -2015,6 +2040,10 @@<br>
LValue EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);<br>
LValue EmitOpaqueValueLValue(const OpaqueValueExpr *e);<br>
<br>
+ RValue EmitPseudoObjectRValue(const PseudoObjectExpr *e,<br>
+ AggValueSlot slot = AggValueSlot::ignored());<br>
+ LValue EmitPseudoObjectLValue(const PseudoObjectExpr *e);<br>
+<br>
llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface,<br>
const ObjCIvarDecl *Ivar);<br>
LValue EmitLValueForAnonRecordField(llvm::Value* Base,<br>
<br>
Modified: cfe/trunk/lib/Rewrite/RewriteObjC.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Rewrite/RewriteObjC.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Rewrite/RewriteObjC.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Rewrite/RewriteObjC.cpp (original)<br>
+++ cfe/trunk/lib/Rewrite/RewriteObjC.cpp Sun Nov 6 03:01:30 2011<br>
@@ -138,12 +138,6 @@<br>
<br>
llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs;<br>
<br>
- // This maps a property to it's assignment statement.<br>
- llvm::DenseMap<Expr *, BinaryOperator *> PropSetters;<br>
- // This maps a property to it's synthesied message expression.<br>
- // This allows us to rewrite chained getters (e.g. o.a.b.c).<br>
- llvm::DenseMap<Expr *, Stmt *> PropGetters;<br>
-<br>
// This maps an original source AST to it's rewritten form. This allows<br>
// us to avoid rewriting the same node twice (which is very uncommon).<br>
// This is needed to support some of the exotic property rewriting.<br>
@@ -154,6 +148,19 @@<br>
VarDecl *GlobalVarDecl;<br>
<br>
bool DisableReplaceStmt;<br>
+ class DisableReplaceStmtScope {<br>
+ RewriteObjC &R;<br>
+ bool SavedValue;<br>
+<br>
+ public:<br>
+ DisableReplaceStmtScope(RewriteObjC &R)<br>
+ : R(R), SavedValue(R.DisableReplaceStmt) {<br>
+ R.DisableReplaceStmt = true;<br>
+ }<br>
+ ~DisableReplaceStmtScope() {<br>
+ R.DisableReplaceStmt = SavedValue;<br>
+ }<br>
+ };<br>
<br>
static const int OBJC_ABI_VERSION = 7;<br>
public:<br>
@@ -186,7 +193,7 @@<br>
return; // We can't rewrite the same node twice.<br>
<br>
if (DisableReplaceStmt)<br>
- return; // Used when rewriting the assignment of a property setter.<br>
+ return;<br>
<br>
// If replacement succeeded or warning disabled return with no warning.<br>
if (!Rewrite.ReplaceStmt(Old, New)) {<br>
@@ -200,6 +207,9 @@<br>
}<br>
<br>
void ReplaceStmtWithRange(Stmt *Old, Stmt *New, SourceRange SrcRange) {<br>
+ if (DisableReplaceStmt)<br>
+ return;<br>
+<br>
// Measure the old text.<br>
int Size = Rewrite.getRangeSize(SrcRange);<br>
if (Size == -1) {<br>
@@ -282,18 +292,14 @@<br>
<br>
// Expression Rewriting.<br>
Stmt *RewriteFunctionBodyOrGlobalInitializer(Stmt *S);<br>
- void CollectPropertySetters(Stmt *S);<br>
<br>
Stmt *CurrentBody;<br>
ParentMap *PropParentMap; // created lazily.<br>
<br>
Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp);<br>
- Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, SourceLocation OrigStart,<br>
- bool &replaced);<br>
- Stmt *RewriteObjCNestedIvarRefExpr(Stmt *S, bool &replaced);<br>
- Stmt *RewritePropertyOrImplicitGetter(Expr *PropOrGetterRefExpr);<br>
- Stmt *RewritePropertyOrImplicitSetter(BinaryOperator *BinOp, Expr *newStmt,<br>
- SourceRange SrcRange);<br>
+ Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV);<br>
+ Stmt *RewritePropertyOrImplicitGetter(PseudoObjectExpr *Pseudo);<br>
+ Stmt *RewritePropertyOrImplicitSetter(PseudoObjectExpr *Pseudo);<br>
Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp);<br>
Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp);<br>
Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp);<br>
@@ -1281,184 +1287,173 @@<br>
"/* @end */");<br>
}<br>
<br>
-Stmt *RewriteObjC::RewritePropertyOrImplicitSetter(BinaryOperator *BinOp, Expr *newStmt,<br>
- SourceRange SrcRange) {<br>
- ObjCMethodDecl *OMD = 0;<br>
- QualType Ty;<br>
- Selector Sel;<br>
- Stmt *Receiver = 0;<br>
- bool Super = false;<br>
- QualType SuperTy;<br>
- SourceLocation SuperLocation;<br>
- SourceLocation SelectorLoc;<br>
- // Synthesize a ObjCMessageExpr from a ObjCPropertyRefExpr or ObjCImplicitSetterGetterRefExpr.<br>
- // This allows us to reuse all the fun and games in SynthMessageExpr().<br>
- if (ObjCPropertyRefExpr *PropRefExpr =<br>
- dyn_cast<ObjCPropertyRefExpr>(BinOp->getLHS())) {<br>
- SelectorLoc = PropRefExpr->getLocation();<br>
- if (PropRefExpr->isExplicitProperty()) {<br>
- ObjCPropertyDecl *PDecl = PropRefExpr->getExplicitProperty();<br>
- OMD = PDecl->getSetterMethodDecl();<br>
- Ty = PDecl->getType();<br>
- Sel = PDecl->getSetterName();<br>
- } else {<br>
- OMD = PropRefExpr->getImplicitPropertySetter();<br>
- Sel = OMD->getSelector();<br>
- Ty = (*OMD->param_begin())->getType();<br>
- }<br>
- Super = PropRefExpr->isSuperReceiver();<br>
- if (!Super) {<br>
- Receiver = PropRefExpr->getBase();<br>
- } else {<br>
- SuperTy = PropRefExpr->getSuperReceiverType();<br>
- SuperLocation = PropRefExpr->getReceiverLocation();<br>
- }<br>
- }<br>
-<br>
- assert(OMD && "RewritePropertyOrImplicitSetter - null OMD");<br>
+Stmt *RewriteObjC::RewritePropertyOrImplicitSetter(PseudoObjectExpr *PseudoOp) {<br>
+ SourceRange OldRange = PseudoOp->getSourceRange();<br>
<br>
- ObjCMessageExpr *MsgExpr;<br>
- if (Super)<br>
- MsgExpr = ObjCMessageExpr::Create(*Context,<br>
- Ty.getNonReferenceType(),<br>
- Expr::getValueKindForType(Ty),<br>
- /*FIXME?*/SourceLocation(),<br>
- SuperLocation,<br>
- /*IsInstanceSuper=*/true,<br>
- SuperTy,<br>
- Sel, SelectorLoc, OMD,<br>
- newStmt,<br>
- /*FIXME:*/SourceLocation());<br>
- else {<br>
- // FIXME. Refactor this into common code with that in<br>
- // RewritePropertyOrImplicitGetter<br>
- assert(Receiver && "RewritePropertyOrImplicitSetter - null Receiver");<br>
- if (Expr *Exp = dyn_cast<Expr>(Receiver))<br>
- if (PropGetters[Exp])<br>
- // This allows us to handle chain/nested property/implicit getters.<br>
- Receiver = PropGetters[Exp];<br>
-<br>
- MsgExpr = ObjCMessageExpr::Create(*Context,<br>
- Ty.getNonReferenceType(),<br>
- Expr::getValueKindForType(Ty),<br>
- /*FIXME: */SourceLocation(),<br>
- cast<Expr>(Receiver),<br>
- Sel, SelectorLoc, OMD,<br>
- newStmt,<br>
- /*FIXME:*/SourceLocation());<br>
+ // We just magically know some things about the structure of this<br>
+ // expression.<br>
+ ObjCMessageExpr *OldMsg =<br>
+ cast<ObjCMessageExpr>(PseudoOp->getSemanticExpr(<br>
+ PseudoOp->getNumSemanticExprs() - 1));<br>
+<br>
+ // Because the rewriter doesn't allow us to rewrite rewritten code,<br>
+ // we need to suppress rewriting the sub-statements.<br>
+ Expr *Base, *RHS;<br>
+ {<br>
+ DisableReplaceStmtScope S(*this);<br>
+<br>
+ // Rebuild the base expression if we have one.<br>
+ Base = 0;<br>
+ if (OldMsg->getReceiverKind() == ObjCMessageExpr::Instance) {<br>
+ Base = OldMsg->getInstanceReceiver();<br>
+ Base = cast<OpaqueValueExpr>(Base)->getSourceExpr();<br>
+ Base = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(Base));<br>
+ }<br>
+<br>
+ // Rebuild the RHS.<br>
+ RHS = cast<BinaryOperator>(PseudoOp->getSyntacticForm())->getRHS();<br>
+ RHS = cast<OpaqueValueExpr>(RHS)->getSourceExpr();<br>
+ RHS = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(RHS));<br>
+ }<br>
+<br>
+ // TODO: avoid this copy.<br>
+ SmallVector<SourceLocation, 1> SelLocs;<br>
+ OldMsg->getSelectorLocs(SelLocs);<br>
+<br>
+ ObjCMessageExpr *NewMsg;<br>
+ switch (OldMsg->getReceiverKind()) {<br>
+ case ObjCMessageExpr::Class:<br>
+ NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),<br>
+ OldMsg->getValueKind(),<br>
+ OldMsg->getLeftLoc(),<br>
+ OldMsg->getClassReceiverTypeInfo(),<br>
+ OldMsg->getSelector(),<br>
+ SelLocs,<br>
+ OldMsg->getMethodDecl(),<br>
+ RHS,<br>
+ OldMsg->getRightLoc());<br>
+ break;<br>
+<br>
+ case ObjCMessageExpr::Instance:<br>
+ NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),<br>
+ OldMsg->getValueKind(),<br>
+ OldMsg->getLeftLoc(),<br>
+ Base,<br>
+ OldMsg->getSelector(),<br>
+ SelLocs,<br>
+ OldMsg->getMethodDecl(),<br>
+ RHS,<br>
+ OldMsg->getRightLoc());<br>
+ break;<br>
+<br>
+ case ObjCMessageExpr::SuperClass:<br>
+ case ObjCMessageExpr::SuperInstance:<br>
+ NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),<br>
+ OldMsg->getValueKind(),<br>
+ OldMsg->getLeftLoc(),<br>
+ OldMsg->getSuperLoc(),<br>
+ OldMsg->getReceiverKind() == ObjCMessageExpr::SuperInstance,<br>
+ OldMsg->getSuperType(),<br>
+ OldMsg->getSelector(),<br>
+ SelLocs,<br>
+ OldMsg->getMethodDecl(),<br>
+ RHS,<br>
+ OldMsg->getRightLoc());<br>
+ break;<br>
}<br>
- Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr);<br>
<br>
- // Now do the actual rewrite.<br>
- ReplaceStmtWithRange(BinOp, ReplacingStmt, SrcRange);<br>
- //delete BinOp;<br>
- // NOTE: We don't want to call MsgExpr->Destroy(), as it holds references<br>
- // to things that stay around.<br>
- Context->Deallocate(MsgExpr);<br>
- return ReplacingStmt;<br>
+ Stmt *Replacement = SynthMessageExpr(NewMsg);<br>
+ ReplaceStmtWithRange(PseudoOp, Replacement, OldRange);<br>
+ return Replacement;<br>
}<br>
<br>
-Stmt *RewriteObjC::RewritePropertyOrImplicitGetter(Expr *PropOrGetterRefExpr) {<br>
- // Synthesize a ObjCMessageExpr from a ObjCPropertyRefExpr or ImplicitGetter.<br>
- // This allows us to reuse all the fun and games in SynthMessageExpr().<br>
- Stmt *Receiver = 0;<br>
- ObjCMethodDecl *OMD = 0;<br>
- QualType Ty;<br>
- Selector Sel;<br>
- bool Super = false;<br>
- QualType SuperTy;<br>
- SourceLocation SuperLocation;<br>
- SourceLocation SelectorLoc;<br>
- if (ObjCPropertyRefExpr *PropRefExpr =<br>
- dyn_cast<ObjCPropertyRefExpr>(PropOrGetterRefExpr)) {<br>
- SelectorLoc = PropRefExpr->getLocation();<br>
- if (PropRefExpr->isExplicitProperty()) {<br>
- ObjCPropertyDecl *PDecl = PropRefExpr->getExplicitProperty();<br>
- OMD = PDecl->getGetterMethodDecl();<br>
- Ty = PDecl->getType();<br>
- Sel = PDecl->getGetterName();<br>
- } else {<br>
- OMD = PropRefExpr->getImplicitPropertyGetter();<br>
- Sel = OMD->getSelector();<br>
- Ty = OMD->getResultType();<br>
- }<br>
- Super = PropRefExpr->isSuperReceiver();<br>
- if (!Super)<br>
- Receiver = PropRefExpr->getBase();<br>
- else {<br>
- SuperTy = PropRefExpr->getSuperReceiverType();<br>
- SuperLocation = PropRefExpr->getReceiverLocation();<br>
+Stmt *RewriteObjC::RewritePropertyOrImplicitGetter(PseudoObjectExpr *PseudoOp) {<br>
+ SourceRange OldRange = PseudoOp->getSourceRange();<br>
+<br>
+ // We just magically know some things about the structure of this<br>
+ // expression.<br>
+ ObjCMessageExpr *OldMsg =<br>
+ cast<ObjCMessageExpr>(PseudoOp->getResultExpr()->IgnoreImplicit());<br>
+<br>
+ // Because the rewriter doesn't allow us to rewrite rewritten code,<br>
+ // we need to suppress rewriting the sub-statements.<br>
+ Expr *Base = 0;<br>
+ {<br>
+ DisableReplaceStmtScope S(*this);<br>
+<br>
+ // Rebuild the base expression if we have one.<br>
+ if (OldMsg->getReceiverKind() == ObjCMessageExpr::Instance) {<br>
+ Base = OldMsg->getInstanceReceiver();<br>
+ Base = cast<OpaqueValueExpr>(Base)->getSourceExpr();<br>
+ Base = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(Base));<br>
}<br>
}<br>
-<br>
- assert (OMD && "RewritePropertyOrImplicitGetter - OMD is null");<br>
-<br>
- ObjCMessageExpr *MsgExpr;<br>
- if (Super)<br>
- MsgExpr = ObjCMessageExpr::Create(*Context,<br>
- Ty.getNonReferenceType(),<br>
- Expr::getValueKindForType(Ty),<br>
- PropOrGetterRefExpr->getLocStart(),<br>
- SuperLocation,<br>
- /*IsInstanceSuper=*/true,<br>
- SuperTy,<br>
- Sel, SelectorLoc, OMD,<br>
- ArrayRef<Expr*>(),<br>
- PropOrGetterRefExpr->getLocEnd());<br>
- else {<br>
- assert (Receiver && "RewritePropertyOrImplicitGetter - Receiver is null");<br>
- if (Expr *Exp = dyn_cast<Expr>(Receiver))<br>
- if (PropGetters[Exp])<br>
- // This allows us to handle chain/nested property/implicit getters.<br>
- Receiver = PropGetters[Exp];<br>
- MsgExpr = ObjCMessageExpr::Create(*Context,<br>
- Ty.getNonReferenceType(),<br>
- Expr::getValueKindForType(Ty),<br>
- PropOrGetterRefExpr->getLocStart(),<br>
- cast<Expr>(Receiver),<br>
- Sel, SelectorLoc, OMD,<br>
- ArrayRef<Expr*>(),<br>
- PropOrGetterRefExpr->getLocEnd());<br>
- }<br>
-<br>
- Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr, MsgExpr->getLocStart(),<br>
- MsgExpr->getLocEnd());<br>
-<br>
- if (!PropParentMap)<br>
- PropParentMap = new ParentMap(CurrentBody);<br>
- bool NestedPropertyRef = false;<br>
- Stmt *Parent = PropParentMap->getParent(PropOrGetterRefExpr);<br>
- ImplicitCastExpr*ICE=0;<br>
- if (Parent)<br>
- if ((ICE = dyn_cast<ImplicitCastExpr>(Parent))) {<br>
- assert((ICE->getCastKind() == CK_GetObjCProperty)<br>
- && "RewritePropertyOrImplicitGetter");<br>
- Parent = PropParentMap->getParent(Parent);<br>
- NestedPropertyRef = (Parent && isa<ObjCPropertyRefExpr>(Parent));<br>
- }<br>
- if (NestedPropertyRef) {<br>
- // We stash away the ReplacingStmt since actually doing the<br>
- // replacement/rewrite won't work for nested getters (e.g. obj.p.i)<br>
- PropGetters[ICE] = ReplacingStmt;<br>
- // NOTE: We don't want to call MsgExpr->Destroy(), as it holds references<br>
- // to things that stay around.<br>
- Context->Deallocate(MsgExpr);<br>
- return PropOrGetterRefExpr; // return the original...<br>
- } else {<br>
- ReplaceStmt(PropOrGetterRefExpr, ReplacingStmt);<br>
- // delete PropRefExpr; elsewhere...<br>
- // NOTE: We don't want to call MsgExpr->Destroy(), as it holds references<br>
- // to things that stay around.<br>
- Context->Deallocate(MsgExpr);<br>
- return ReplacingStmt;<br>
+<br>
+ // Intentionally empty.<br>
+ SmallVector<SourceLocation, 1> SelLocs;<br>
+ SmallVector<Expr*, 1> Args;<br>
+<br>
+ ObjCMessageExpr *NewMsg;<br>
+ switch (OldMsg->getReceiverKind()) {<br>
+ case ObjCMessageExpr::Class:<br>
+ NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),<br>
+ OldMsg->getValueKind(),<br>
+ OldMsg->getLeftLoc(),<br>
+ OldMsg->getClassReceiverTypeInfo(),<br>
+ OldMsg->getSelector(),<br>
+ SelLocs,<br>
+ OldMsg->getMethodDecl(),<br>
+ Args,<br>
+ OldMsg->getRightLoc());<br>
+ break;<br>
+<br>
+ case ObjCMessageExpr::Instance:<br>
+ NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),<br>
+ OldMsg->getValueKind(),<br>
+ OldMsg->getLeftLoc(),<br>
+ Base,<br>
+ OldMsg->getSelector(),<br>
+ SelLocs,<br>
+ OldMsg->getMethodDecl(),<br>
+ Args,<br>
+ OldMsg->getRightLoc());<br>
+ break;<br>
+<br>
+ case ObjCMessageExpr::SuperClass:<br>
+ case ObjCMessageExpr::SuperInstance:<br>
+ NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),<br>
+ OldMsg->getValueKind(),<br>
+ OldMsg->getLeftLoc(),<br>
+ OldMsg->getSuperLoc(),<br>
+ OldMsg->getReceiverKind() == ObjCMessageExpr::SuperInstance,<br>
+ OldMsg->getSuperType(),<br>
+ OldMsg->getSelector(),<br>
+ SelLocs,<br>
+ OldMsg->getMethodDecl(),<br>
+ Args,<br>
+ OldMsg->getRightLoc());<br>
+ break;<br>
}<br>
+<br>
+ Stmt *Replacement = SynthMessageExpr(NewMsg);<br>
+ ReplaceStmtWithRange(PseudoOp, Replacement, OldRange);<br>
+ return Replacement;<br>
}<br>
<br>
-Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,<br>
- SourceLocation OrigStart,<br>
- bool &replaced) {<br>
+Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {<br>
+ SourceRange OldRange = IV->getSourceRange();<br>
+ Expr *BaseExpr = IV->getBase();<br>
+<br>
+ // Rewrite the base, but without actually doing replaces.<br>
+ {<br>
+ DisableReplaceStmtScope S(*this);<br>
+ BaseExpr = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(BaseExpr));<br>
+ IV->setBase(BaseExpr);<br>
+ }<br>
+<br>
ObjCIvarDecl *D = IV->getDecl();<br>
- const Expr *BaseExpr = IV->getBase();<br>
+<br>
+ Expr *Replacement = IV;<br>
if (CurMethodDef) {<br>
if (BaseExpr->getType()->isObjCObjectPointerType()) {<br>
const ObjCInterfaceType *iFaceDecl =<br>
@@ -1483,25 +1478,19 @@<br>
CK_BitCast,<br>
IV->getBase());<br>
// Don't forget the parens to enforce the proper binding.<br>
- ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(),<br>
- IV->getBase()->getLocEnd(),<br>
+ ParenExpr *PE = new (Context) ParenExpr(OldRange.getBegin(),<br>
+ OldRange.getEnd(),<br>
castExpr);<br>
- replaced = true;<br>
if (IV->isFreeIvar() &&<br>
CurMethodDef->getClassInterface() == iFaceDecl->getDecl()) {<br>
MemberExpr *ME = new (Context) MemberExpr(PE, true, D,<br>
IV->getLocation(),<br>
D->getType(),<br>
VK_LValue, OK_Ordinary);<br>
- // delete IV; leak for now, see RewritePropertyOrImplicitSetter() usage for more info.<br>
- return ME;<br>
+ Replacement = ME;<br>
+ } else {<br>
+ IV->setBase(PE);<br>
}<br>
- // Get the new text<br>
- // Cannot delete IV->getBase(), since PE points to it.<br>
- // Replace the old base with the cast. This is important when doing<br>
- // embedded rewrites. For example, [newInv->_container addObject:0].<br>
- IV->setBase(PE);<br>
- return IV;<br>
}<br>
} else { // we are outside a method.<br>
assert(!IV->isFreeIvar() && "Cannot have a free standing ivar outside a method");<br>
@@ -1532,36 +1521,15 @@<br>
// Don't forget the parens to enforce the proper binding.<br>
ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(),<br>
IV->getBase()->getLocEnd(), castExpr);<br>
- replaced = true;<br>
// Cannot delete IV->getBase(), since PE points to it.<br>
// Replace the old base with the cast. This is important when doing<br>
// embedded rewrites. For example, [newInv->_container addObject:0].<br>
IV->setBase(PE);<br>
- return IV;<br>
}<br>
}<br>
- return IV;<br>
-}<br>
<br>
-Stmt *RewriteObjC::RewriteObjCNestedIvarRefExpr(Stmt *S, bool &replaced) {<br>
- for (Stmt::child_range CI = S->children(); CI; ++CI) {<br>
- if (*CI) {<br>
- Stmt *newStmt = RewriteObjCNestedIvarRefExpr(*CI, replaced);<br>
- if (newStmt)<br>
- *CI = newStmt;<br>
- }<br>
- }<br>
- if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) {<br>
- SourceRange OrigStmtRange = S->getSourceRange();<br>
- Stmt *newStmt = RewriteObjCIvarRefExpr(IvarRefExpr, OrigStmtRange.getBegin(),<br>
- replaced);<br>
- return newStmt;<br>
- }<br>
- if (ObjCMessageExpr *MsgRefExpr = dyn_cast<ObjCMessageExpr>(S)) {<br>
- Stmt *newStmt = SynthMessageExpr(MsgRefExpr);<br>
- return newStmt;<br>
- }<br>
- return S;<br>
+ ReplaceStmtWithRange(IV, Replacement, OldRange);<br>
+ return Replacement;<br>
}<br>
<br>
/// SynthCountByEnumWithState - To print:<br>
@@ -4753,6 +4721,9 @@<br>
return CondExpr;<br>
} else if (const ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(BlockExp)) {<br>
CPT = IRE->getType()->getAs<BlockPointerType>();<br>
+ } else if (const PseudoObjectExpr *POE<br>
+ = dyn_cast<PseudoObjectExpr>(BlockExp)) {<br>
+ CPT = POE->getType()->castAs<BlockPointerType>();<br>
} else {<br>
assert(1 && "RewriteBlockClass: Bad type");<br>
}<br>
@@ -5580,26 +5551,6 @@<br>
// Function Body / Expression rewriting<br>
//===----------------------------------------------------------------------===//<br>
<br>
-// This is run as a first "pass" prior to RewriteFunctionBodyOrGlobalInitializer().<br>
-// The allows the main rewrite loop to associate all ObjCPropertyRefExprs with<br>
-// their respective BinaryOperator. Without this knowledge, we'd need to rewrite<br>
-// the ObjCPropertyRefExpr twice (once as a getter, and later as a setter).<br>
-// Since the rewriter isn't capable of rewriting rewritten code, it's important<br>
-// we get this right.<br>
-void RewriteObjC::CollectPropertySetters(Stmt *S) {<br>
- // Perform a bottom up traversal of all children.<br>
- for (Stmt::child_range CI = S->children(); CI; ++CI)<br>
- if (*CI)<br>
- CollectPropertySetters(*CI);<br>
-<br>
- if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) {<br>
- if (BinOp->isAssignmentOp()) {<br>
- if (isa<ObjCPropertyRefExpr>(BinOp->getLHS()))<br>
- PropSetters[BinOp->getLHS()] = BinOp;<br>
- }<br>
- }<br>
-}<br>
-<br>
Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {<br>
if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) ||<br>
isa<DoStmt>(S) || isa<ForStmt>(S))<br>
@@ -5609,46 +5560,28 @@<br>
ObjCBcLabelNo.push_back(++BcLabelCount);<br>
}<br>
<br>
+ // Pseudo-object operations and ivar references need special<br>
+ // treatment because we're going to recursively rewrite them.<br>
+ if (PseudoObjectExpr *PseudoOp = dyn_cast<PseudoObjectExpr>(S)) {<br>
+ if (isa<BinaryOperator>(PseudoOp->getSyntacticForm())) {<br>
+ return RewritePropertyOrImplicitSetter(PseudoOp);<br>
+ } else {<br>
+ return RewritePropertyOrImplicitGetter(PseudoOp);<br>
+ }<br>
+ } else if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) {<br>
+ return RewriteObjCIvarRefExpr(IvarRefExpr);<br>
+ }<br>
+<br>
SourceRange OrigStmtRange = S->getSourceRange();<br>
<br>
// Perform a bottom up rewrite of all children.<br>
for (Stmt::child_range CI = S->children(); CI; ++CI)<br>
if (*CI) {<br>
- Stmt *newStmt;<br>
- Stmt *ChildStmt = (*CI);<br>
- if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(ChildStmt)) {<br>
- Expr *OldBase = IvarRefExpr->getBase();<br>
- bool replaced = false;<br>
- newStmt = RewriteObjCNestedIvarRefExpr(ChildStmt, replaced);<br>
- if (replaced) {<br>
- if (ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(newStmt))<br>
- ReplaceStmt(OldBase, IRE->getBase());<br>
- else<br>
- ReplaceStmt(ChildStmt, newStmt);<br>
- }<br>
- }<br>
- else<br>
- newStmt = RewriteFunctionBodyOrGlobalInitializer(ChildStmt);<br>
+ Stmt *childStmt = (*CI);<br>
+ Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(childStmt);<br>
if (newStmt) {<br>
- if (Expr *PropOrImplicitRefExpr = dyn_cast<Expr>(ChildStmt))<br>
- if (PropSetters[PropOrImplicitRefExpr] == S) {<br>
- S = newStmt;<br>
- newStmt = 0;<br>
- }<br>
- if (newStmt)<br>
- *CI = newStmt;<br>
- }<br>
- // If dealing with an assignment with LHS being a property reference<br>
- // expression, the entire assignment tree is rewritten into a property<br>
- // setter messaging. This involvs the RHS too. Do not attempt to rewrite<br>
- // RHS again.<br>
- if (Expr *Exp = dyn_cast<Expr>(ChildStmt))<br>
- if (isa<ObjCPropertyRefExpr>(Exp)) {<br>
- if (PropSetters[Exp]) {<br>
- ++CI;<br>
- continue;<br>
- }<br>
- }<br>
+ *CI = newStmt;<br>
+ }<br>
}<br>
<br>
if (BlockExpr *BE = dyn_cast<BlockExpr>(S)) {<br>
@@ -5661,7 +5594,6 @@<br>
// Rewrite the block body in place.<br>
Stmt *SaveCurrentBody = CurrentBody;<br>
CurrentBody = BE->getBody();<br>
- CollectPropertySetters(CurrentBody);<br>
PropParentMap = 0;<br>
// block literal on rhs of a property-dot-sytax assignment<br>
// must be replaced by its synthesize ast so getRewrittenText<br>
@@ -5689,67 +5621,6 @@<br>
if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))<br>
return RewriteAtEncode(AtEncode);<br>
<br>
- if (isa<ObjCPropertyRefExpr>(S)) {<br>
- Expr *PropOrImplicitRefExpr = dyn_cast<Expr>(S);<br>
- assert(PropOrImplicitRefExpr && "Property or implicit setter/getter is null");<br>
-<br>
- BinaryOperator *BinOp = PropSetters[PropOrImplicitRefExpr];<br>
- if (BinOp) {<br>
- // Because the rewriter doesn't allow us to rewrite rewritten code,<br>
- // we need to rewrite the right hand side prior to rewriting the setter.<br>
- DisableReplaceStmt = true;<br>
- // Save the source range. Even if we disable the replacement, the<br>
- // rewritten node will have been inserted into the tree. If the synthesized<br>
- // node is at the 'end', the rewriter will fail. Consider this:<br>
- // self.errorHandler = handler ? handler :<br>
- // ^(NSURL *errorURL, NSError *error) { return (BOOL)1; };<br>
- SourceRange SrcRange = BinOp->getSourceRange();<br>
- Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(BinOp->getRHS());<br>
- // Need to rewrite the ivar access expression if need be.<br>
- if (isa<ObjCIvarRefExpr>(newStmt)) {<br>
- bool replaced = false;<br>
- newStmt = RewriteObjCNestedIvarRefExpr(newStmt, replaced);<br>
- }<br>
-<br>
- DisableReplaceStmt = false;<br>
- //<br>
- // Unlike the main iterator, we explicily avoid changing 'BinOp'. If<br>
- // we changed the RHS of BinOp, the rewriter would fail (since it needs<br>
- // to see the original expression). Consider this example:<br>
- //<br>
- // Foo *obj1, *obj2;<br>
- //<br>
- // obj1.i = [obj2 rrrr];<br>
- //<br>
- // 'BinOp' for the previous expression looks like:<br>
- //<br>
- // (BinaryOperator 0x231ccf0 'int' '='<br>
- // (ObjCPropertyRefExpr 0x231cc70 'int' Kind=PropertyRef Property="i"<br>
- // (DeclRefExpr 0x231cc50 'Foo *' Var='obj1' 0x231cbb0))<br>
- // (ObjCMessageExpr 0x231ccb0 'int' selector=rrrr<br>
- // (DeclRefExpr 0x231cc90 'Foo *' Var='obj2' 0x231cbe0)))<br>
- //<br>
- // 'newStmt' represents the rewritten message expression. For example:<br>
- //<br>
- // (CallExpr 0x231d300 'id':'struct objc_object *'<br>
- // (ParenExpr 0x231d2e0 'int (*)(id, SEL)'<br>
- // (CStyleCastExpr 0x231d2c0 'int (*)(id, SEL)'<br>
- // (CStyleCastExpr 0x231d220 'void *'<br>
- // (DeclRefExpr 0x231d200 'id (id, SEL, ...)' FunctionDecl='objc_msgSend' 0x231cdc0))))<br>
- //<br>
- // Note that 'newStmt' is passed to RewritePropertyOrImplicitSetter so that it<br>
- // can be used as the setter argument. ReplaceStmt() will still 'see'<br>
- // the original RHS (since we haven't altered BinOp).<br>
- //<br>
- // This implies the Rewrite* routines can no longer delete the original<br>
- // node. As a result, we now leak the original AST nodes.<br>
- //<br>
- return RewritePropertyOrImplicitSetter(BinOp, dyn_cast<Expr>(newStmt), SrcRange);<br>
- } else {<br>
- return RewritePropertyOrImplicitGetter(PropOrImplicitRefExpr);<br>
- }<br>
- }<br>
-<br>
if (ObjCSelectorExpr *AtSelector = dyn_cast<ObjCSelectorExpr>(S))<br>
return RewriteAtSelector(AtSelector);<br>
<br>
@@ -5930,7 +5801,6 @@<br>
if (CompoundStmt *Body = dyn_cast_or_null<CompoundStmt>(FD->getBody())) {<br>
CurFunctionDef = FD;<br>
CurFunctionDeclToDeclareForBlock = FD;<br>
- CollectPropertySetters(Body);<br>
CurrentBody = Body;<br>
Body =<br>
cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body));<br>
@@ -5951,7 +5821,6 @@<br>
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {<br>
if (CompoundStmt *Body = MD->getCompoundBody()) {<br>
CurMethodDef = MD;<br>
- CollectPropertySetters(Body);<br>
CurrentBody = Body;<br>
Body =<br>
cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body));<br>
@@ -5989,7 +5858,6 @@<br>
}<br>
if (VD->getInit()) {<br>
GlobalVarDecl = VD;<br>
- CollectPropertySetters(VD->getInit());<br>
CurrentBody = VD->getInit();<br>
RewriteFunctionBodyOrGlobalInitializer(VD->getInit());<br>
CurrentBody = 0;<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaChecking.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Sun Nov 6 03:01:30 2011<br>
@@ -4213,6 +4213,26 @@<br>
continue;<br>
}<br>
<br>
+ if (PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(e)) {<br>
+ // Only pay attention to pseudo-objects on property references.<br>
+ ObjCPropertyRefExpr *pre<br>
+ = dyn_cast<ObjCPropertyRefExpr>(pseudo->getSyntacticForm()<br>
+ ->IgnoreParens());<br>
+ if (!pre) return false;<br>
+ if (pre->isImplicitProperty()) return false;<br>
+ ObjCPropertyDecl *property = pre->getExplicitProperty();<br>
+ if (!property->isRetaining() &&<br>
+ !(property->getPropertyIvarDecl() &&<br>
+ property->getPropertyIvarDecl()->getType()<br>
+ .getObjCLifetime() == Qualifiers::OCL_Strong))<br>
+ return false;<br>
+<br>
+ owner.Indirect = true;<br>
+ e = const_cast<Expr*>(cast<OpaqueValueExpr>(pre->getBase())<br>
+ ->getSourceExpr());<br>
+ continue;<br>
+ }<br>
+<br>
// Array ivars?<br>
<br>
return false;<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Sun Nov 6 03:01:30 2011<br>
@@ -7468,7 +7468,7 @@<br>
// The operand must be either an l-value or a function designator<br>
if (!op->getType()->isFunctionType()) {<br>
// Use a special diagnostic for loads from property references.<br>
- if (isa<ObjCPropertyRefExpr>(op->IgnoreImplicit()->IgnoreParens())) {<br>
+ if (isa<PseudoObjectExpr>(op)) {<br>
AddressOfError = AO_Property_Expansion;<br>
} else {<br>
// FIXME: emit more specific diag...<br>
@@ -7483,9 +7483,6 @@<br>
} else if (op->getObjectKind() == OK_VectorComponent) {<br>
// The operand cannot be an element of a vector<br>
AddressOfError = AO_Vector_Element;<br>
- } else if (op->getObjectKind() == OK_ObjCProperty) {<br>
- // cannot take address of a property expression.<br>
- AddressOfError = AO_Property_Expansion;<br>
} else if (dcl) { // C99 6.5.3.2p1<br>
// We have an lvalue with a decl. Make sure the decl is not declared<br>
// with the register storage-class specifier.<br>
@@ -8951,8 +8948,15 @@<br>
return;<br>
}<br>
<br>
- // Strip off any parens and casts.<br>
- StringLiteral *SL = dyn_cast<StringLiteral>(SrcExpr->IgnoreParenCasts());<br>
+ // Ignore any parens, implicit casts (should only be<br>
+ // array-to-pointer decays), and not-so-opaque values. The last is<br>
+ // important for making this trigger for property assignments.<br>
+ SrcExpr = SrcExpr->IgnoreParenImpCasts();<br>
+ if (OpaqueValueExpr *OV = dyn_cast<OpaqueValueExpr>(SrcExpr))<br>
+ if (OV->getSourceExpr())<br>
+ SrcExpr = OV->getSourceExpr()->IgnoreParenImpCasts();<br>
+<br>
+ StringLiteral *SL = dyn_cast<StringLiteral>(SrcExpr);<br>
if (!SL || !SL->isAscii())<br>
return;<br>
<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Sun Nov 6 03:01:30 2011<br>
@@ -467,14 +467,13 @@<br>
<br>
bool Sema::isSelfExpr(Expr *receiver) {<br>
// 'self' is objc 'self' in an objc method only.<br>
- DeclContext *DC = CurContext;<br>
- while (isa<BlockDecl>(DC))<br>
- DC = DC->getParent();<br>
- if (DC && !isa<ObjCMethodDecl>(DC))<br>
- return false;<br>
+ ObjCMethodDecl *method =<br>
+ dyn_cast<ObjCMethodDecl>(CurContext->getNonClosureAncestor());<br>
+ if (!method) return false;<br>
+<br>
receiver = receiver->IgnoreParenLValueCasts();<br>
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(receiver))<br>
- if (DRE->getDecl()->getIdentifier() == &Context.Idents.get("self"))<br>
+ if (DRE->getDecl() == method->getSelfDecl())<br>
return true;<br>
return false;<br>
}<br>
@@ -1725,6 +1724,12 @@<br>
return merge(left, Visit(e->getFalseExpr()));<br>
}<br>
<br>
+ /// Look through pseudo-objects.<br>
+ ACCResult VisitPseudoObjectExpr(PseudoObjectExpr *e) {<br>
+ // If we're getting here, we should always have a result.<br>
+ return Visit(e->getResultExpr());<br>
+ }<br>
+<br>
/// Statement expressions are okay if their result expression is okay.<br>
ACCResult VisitStmtExpr(StmtExpr *e) {<br>
return Visit(e->getSubStmt()->body_back());<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaPseudoObject.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaPseudoObject.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaPseudoObject.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaPseudoObject.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaPseudoObject.cpp Sun Nov 6 03:01:30 2011<br>
@@ -38,11 +38,364 @@<br>
using namespace clang;<br>
using namespace sema;<br>
<br>
+namespace {<br>
+ // Basically just a very focused copy of TreeTransform.<br>
+ template <class T> struct Rebuilder {<br>
+ Sema &S;<br>
+ Rebuilder(Sema &S) : S(S) {}<br>
+<br>
+ T &getDerived() { return static_cast<T&>(*this); }<br>
+<br>
+ Expr *rebuild(Expr *e) {<br>
+ // Fast path: nothing to look through.<br>
+ if (typename T::specific_type *specific<br>
+ = dyn_cast<typename T::specific_type>(e))<br>
+ return getDerived().rebuildSpecific(specific);<br>
+<br>
+ // Otherwise, we should look through and rebuild anything that<br>
+ // IgnoreParens would.<br>
+<br>
+ if (ParenExpr *parens = dyn_cast<ParenExpr>(e)) {<br>
+ e = rebuild(parens->getSubExpr());<br>
+ return new (S.Context) ParenExpr(parens->getLParen(),<br>
+ parens->getRParen(),<br>
+ e);<br>
+ }<br>
+<br>
+ if (UnaryOperator *uop = dyn_cast<UnaryOperator>(e)) {<br>
+ assert(uop->getOpcode() == UO_Extension);<br>
+ e = rebuild(uop->getSubExpr());<br>
+ return new (S.Context) UnaryOperator(e, uop->getOpcode(),<br>
+ uop->getType(),<br>
+ uop->getValueKind(),<br>
+ uop->getObjectKind(),<br>
+ uop->getOperatorLoc());<br>
+ }<br>
+<br>
+ if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) {<br>
+ assert(!gse->isResultDependent());<br>
+ unsigned resultIndex = gse->getResultIndex();<br>
+ unsigned numAssocs = gse->getNumAssocs();<br>
+<br>
+ SmallVector<Expr*, 8> assocs(numAssocs);<br>
+ SmallVector<TypeSourceInfo*, 8> assocTypes(numAssocs);<br>
+<br>
+ for (unsigned i = 0; i != numAssocs; ++i) {<br>
+ Expr *assoc = gse->getAssocExpr(i);<br>
+ if (i == resultIndex) assoc = rebuild(assoc);<br>
+ assocs[i] = assoc;<br>
+ assocTypes[i] = gse->getAssocTypeSourceInfo(i);<br>
+ }<br>
+<br>
+ return new (S.Context) GenericSelectionExpr(S.Context,<br>
+ gse->getGenericLoc(),<br>
+ gse->getControllingExpr(),<br>
+ assocTypes.data(),<br>
+ assocs.data(),<br>
+ numAssocs,<br>
+ gse->getDefaultLoc(),<br>
+ gse->getRParenLoc(),<br>
+ gse->containsUnexpandedParameterPack(),<br>
+ resultIndex);<br>
+ }<br>
+<br>
+ llvm_unreachable("bad expression to rebuild!");<br>
+ }<br>
+ };<br>
+<br>
+ struct ObjCPropertyRefRebuilder : Rebuilder<ObjCPropertyRefRebuilder> {<br>
+ Expr *NewBase;<br>
+ ObjCPropertyRefRebuilder(Sema &S, Expr *newBase)<br>
+ : Rebuilder(S), NewBase(newBase) {}<br>
+<br>
+ typedef ObjCPropertyRefExpr specific_type;<br>
+ Expr *rebuildSpecific(ObjCPropertyRefExpr *refExpr) {<br>
+ // Fortunately, the constraint that we're rebuilding something<br>
+ // with a base limits the number of cases here.<br>
+ assert(refExpr->getBase());<br>
+<br>
+ if (refExpr->isExplicitProperty()) {<br>
+ return new (S.Context)<br>
+ ObjCPropertyRefExpr(refExpr->getExplicitProperty(),<br>
+ refExpr->getType(), refExpr->getValueKind(),<br>
+ refExpr->getObjectKind(), refExpr->getLocation(),<br>
+ NewBase);<br>
+ }<br>
+ return new (S.Context)<br>
+ ObjCPropertyRefExpr(refExpr->getImplicitPropertyGetter(),<br>
+ refExpr->getImplicitPropertySetter(),<br>
+ refExpr->getType(), refExpr->getValueKind(),<br>
+ refExpr->getObjectKind(),refExpr->getLocation(),<br>
+ NewBase);<br>
+ }<br>
+ };<br>
+<br>
+ class PseudoOpBuilder {<br>
+ public:<br>
+ Sema &S;<br>
+ unsigned ResultIndex;<br>
+ SourceLocation GenericLoc;<br>
+ SmallVector<Expr *, 4> Semantics;<br>
+<br>
+ PseudoOpBuilder(Sema &S, SourceLocation genericLoc)<br>
+ : S(S), ResultIndex(PseudoObjectExpr::NoResult),<br>
+ GenericLoc(genericLoc) {}<br>
+<br>
+ /// Add a normal semantic expression.<br>
+ void addSemanticExpr(Expr *semantic) {<br>
+ Semantics.push_back(semantic);<br>
+ }<br>
+<br>
+ /// Add the 'result' semantic expression.<br>
+ void addResultSemanticExpr(Expr *resultExpr) {<br>
+ assert(ResultIndex == PseudoObjectExpr::NoResult);<br>
+ ResultIndex = Semantics.size();<br>
+ Semantics.push_back(resultExpr);<br>
+ }<br>
+<br>
+ ExprResult buildRValueOperation(Expr *op);<br>
+ ExprResult buildAssignmentOperation(Scope *Sc,<br>
+ SourceLocation opLoc,<br>
+ BinaryOperatorKind opcode,<br>
+ Expr *LHS, Expr *RHS);<br>
+ ExprResult buildIncDecOperation(Scope *Sc, SourceLocation opLoc,<br>
+ UnaryOperatorKind opcode,<br>
+ Expr *op);<br>
+<br>
+ ExprResult complete(Expr *syntacticForm);<br>
+<br>
+ OpaqueValueExpr *capture(Expr *op);<br>
+ OpaqueValueExpr *captureValueAsResult(Expr *op);<br>
+<br>
+ void setResultToLastSemantic() {<br>
+ assert(ResultIndex == PseudoObjectExpr::NoResult);<br>
+ ResultIndex = Semantics.size() - 1;<br>
+ }<br>
+<br>
+ /// Return true if assignments have a non-void result.<br>
+ virtual bool assignmentsHaveResult() { return true; }<br>
+<br>
+ virtual Expr *rebuildAndCaptureObject(Expr *) = 0;<br>
+ virtual ExprResult buildGet() = 0;<br>
+ virtual ExprResult buildSet(Expr *, SourceLocation,<br>
+ bool captureSetValueAsResult) = 0;<br>
+ };<br>
+<br>
+ /// A PseudoOpBuilder for Objective-C @properties.<br>
+ class ObjCPropertyOpBuilder : public PseudoOpBuilder {<br>
+ ObjCPropertyRefExpr *RefExpr;<br>
+ OpaqueValueExpr *InstanceReceiver;<br>
+ ObjCMethodDecl *Getter;<br>
+<br>
+ ObjCMethodDecl *Setter;<br>
+ Selector SetterSelector;<br>
+<br>
+ public:<br>
+ ObjCPropertyOpBuilder(Sema &S, ObjCPropertyRefExpr *refExpr) :<br>
+ PseudoOpBuilder(S, refExpr->getLocation()), RefExpr(refExpr),<br>
+ InstanceReceiver(0), Getter(0), Setter(0) {<br>
+ }<br>
+<br>
+ ExprResult buildRValueOperation(Expr *op);<br>
+ ExprResult buildAssignmentOperation(Scope *Sc,<br>
+ SourceLocation opLoc,<br>
+ BinaryOperatorKind opcode,<br>
+ Expr *LHS, Expr *RHS);<br>
+ ExprResult buildIncDecOperation(Scope *Sc, SourceLocation opLoc,<br>
+ UnaryOperatorKind opcode,<br>
+ Expr *op);<br>
+<br>
+ bool tryBuildGetOfReference(Expr *op, ExprResult &result);<br>
+ bool findSetter();<br>
+ bool findGetter();<br>
+<br>
+ Expr *rebuildAndCaptureObject(Expr *syntacticBase);<br>
+ ExprResult buildGet();<br>
+ ExprResult buildSet(Expr *op, SourceLocation, bool);<br>
+ };<br>
+}<br>
+<br>
+/// Capture the given expression in an OpaqueValueExpr.<br>
+OpaqueValueExpr *PseudoOpBuilder::capture(Expr *e) {<br>
+ // Make a new OVE whose source is the given expression.<br>
+ OpaqueValueExpr *captured =<br>
+ new (S.Context) OpaqueValueExpr(GenericLoc, e->getType(),<br>
+ e->getValueKind());<br>
+ captured->setSourceExpr(e);<br>
+<br>
+ // Make sure we bind that in the semantics.<br>
+ addSemanticExpr(captured);<br>
+ return captured;<br>
+}<br>
+<br>
+/// Capture the given expression as the result of this pseudo-object<br>
+/// operation. This routine is safe against expressions which may<br>
+/// already be captured.<br>
+///<br>
+/// \param Returns the captured expression, which will be the<br>
+/// same as the input if the input was already captured<br>
+OpaqueValueExpr *PseudoOpBuilder::captureValueAsResult(Expr *e) {<br>
+ assert(ResultIndex == PseudoObjectExpr::NoResult);<br>
+<br>
+ // If the expression hasn't already been captured, just capture it<br>
+ // and set the new semantic<br>
+ if (!isa<OpaqueValueExpr>(e)) {<br>
+ OpaqueValueExpr *cap = capture(e);<br>
+ setResultToLastSemantic();<br>
+ return cap;<br>
+ }<br>
+<br>
+ // Otherwise, it must already be one of our semantic expressions;<br>
+ // set ResultIndex to its index.<br>
+ unsigned index = 0;<br>
+ for (;; ++index) {<br>
+ assert(index < Semantics.size() &&<br>
+ "captured expression not found in semantics!");<br>
+ if (e == Semantics[index]) break;<br>
+ }<br>
+ ResultIndex = index;<br>
+ return cast<OpaqueValueExpr>(e);<br>
+}<br>
+<br>
+/// The routine which creates the final PseudoObjectExpr.<br>
+ExprResult PseudoOpBuilder::complete(Expr *syntactic) {<br>
+ return PseudoObjectExpr::Create(S.Context, syntactic,<br>
+ Semantics, ResultIndex);<br>
+}<br>
+<br>
+/// The main skeleton for building an r-value operation.<br>
+ExprResult PseudoOpBuilder::buildRValueOperation(Expr *op) {<br>
+ Expr *syntacticBase = rebuildAndCaptureObject(op);<br>
+<br>
+ ExprResult getExpr = buildGet();<br>
+ if (getExpr.isInvalid()) return ExprError();<br>
+ addResultSemanticExpr(getExpr.take());<br>
+<br>
+ return complete(syntacticBase);<br>
+}<br>
+<br>
+/// The basic skeleton for building a simple or compound<br>
+/// assignment operation.<br>
+ExprResult<br>
+PseudoOpBuilder::buildAssignmentOperation(Scope *Sc, SourceLocation opcLoc,<br>
+ BinaryOperatorKind opcode,<br>
+ Expr *LHS, Expr *RHS) {<br>
+ assert(BinaryOperator::isAssignmentOp(opcode));<br>
+<br>
+ Expr *syntacticLHS = rebuildAndCaptureObject(LHS);<br>
+ OpaqueValueExpr *capturedRHS = capture(RHS);<br>
+<br>
+ Expr *syntactic;<br>
+<br>
+ ExprResult result;<br>
+ if (opcode == BO_Assign) {<br>
+ result = capturedRHS;<br>
+ syntactic = new (S.Context) BinaryOperator(syntacticLHS, capturedRHS,<br>
+ opcode, capturedRHS->getType(),<br>
+ capturedRHS->getValueKind(),<br>
+ OK_Ordinary, opcLoc);<br>
+ } else {<br>
+ ExprResult opLHS = buildGet();<br>
+ if (opLHS.isInvalid()) return ExprError();<br>
+<br>
+ // Build an ordinary, non-compound operation.<br>
+ BinaryOperatorKind nonCompound =<br>
+ BinaryOperator::getOpForCompoundAssignment(opcode);<br>
+ result = S.BuildBinOp(Sc, opcLoc, nonCompound,<br>
+ opLHS.take(), capturedRHS);<br>
+ if (result.isInvalid()) return ExprError();<br>
+<br>
+ syntactic =<br>
+ new (S.Context) CompoundAssignOperator(syntacticLHS, capturedRHS, opcode,<br>
+ result.get()->getType(),<br>
+ result.get()->getValueKind(),<br>
+ OK_Ordinary,<br>
+ opLHS.get()->getType(),<br>
+ result.get()->getType(),<br>
+ opcLoc);<br>
+ }<br>
+<br>
+ // The result of the assignment, if not void, is the value set into<br>
+ // the l-value.<br>
+ result = buildSet(result.take(), opcLoc, assignmentsHaveResult());<br>
+ if (result.isInvalid()) return ExprError();<br>
+ addSemanticExpr(result.take());<br>
+<br>
+ return complete(syntactic);<br>
+}<br>
+<br>
+/// The basic skeleton for building an increment or decrement<br>
+/// operation.<br>
+ExprResult<br>
+PseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc,<br>
+ UnaryOperatorKind opcode,<br>
+ Expr *op) {<br>
+ assert(UnaryOperator::isIncrementDecrementOp(opcode));<br>
+<br>
+ Expr *syntacticOp = rebuildAndCaptureObject(op);<br>
+<br>
+ // Load the value.<br>
+ ExprResult result = buildGet();<br>
+ if (result.isInvalid()) return ExprError();<br>
+<br>
+ QualType resultType = result.get()->getType();<br>
+<br>
+ // That's the postfix result.<br>
+ if (UnaryOperator::isPostfix(opcode) && assignmentsHaveResult()) {<br>
+ result = capture(result.take());<br>
+ setResultToLastSemantic();<br>
+ }<br>
+<br>
+ // Add or subtract a literal 1.<br>
+ llvm::APInt oneV(S.Context.getTypeSize(S.Context.IntTy), 1);<br>
+ Expr *one = IntegerLiteral::Create(S.Context, oneV, S.Context.IntTy,<br>
+ GenericLoc);<br>
+<br>
+ if (UnaryOperator::isIncrementOp(opcode)) {<br>
+ result = S.BuildBinOp(Sc, opcLoc, BO_Add, result.take(), one);<br>
+ } else {<br>
+ result = S.BuildBinOp(Sc, opcLoc, BO_Sub, result.take(), one);<br>
+ }<br>
+ if (result.isInvalid()) return ExprError();<br>
+<br>
+ // Store that back into the result. The value stored is the result<br>
+ // of a prefix operation.<br>
+ result = buildSet(result.take(), opcLoc,<br>
+ UnaryOperator::isPrefix(opcode) && assignmentsHaveResult());<br>
+ if (result.isInvalid()) return ExprError();<br>
+ addSemanticExpr(result.take());<br>
+<br>
+ UnaryOperator *syntactic =<br>
+ new (S.Context) UnaryOperator(syntacticOp, opcode, resultType,<br>
+ VK_LValue, OK_Ordinary, opcLoc);<br>
+ return complete(syntactic);<br>
+}<br>
+<br>
+<br>
+//===----------------------------------------------------------------------===//<br>
+// Objective-C @property and implicit property references<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+/// Look up a method in the receiver type of an Objective-C property<br>
+/// reference.<br>
static ObjCMethodDecl *LookupMethodInReceiverType(Sema &S, Selector sel,<br>
const ObjCPropertyRefExpr *PRE) {<br>
if (PRE->isObjectReceiver()) {<br>
const ObjCObjectPointerType *PT =<br>
PRE->getBase()->getType()->castAs<ObjCObjectPointerType>();<br>
+<br>
+ // Special case for 'self' in class method implementations.<br>
+ if (PT->isObjCClassType() &&<br>
+ S.isSelfExpr(const_cast<Expr*>(PRE->getBase()))) {<br>
+ // This cast is safe because isSelfExpr is only true within<br>
+ // methods.<br>
+ ObjCMethodDecl *method =<br>
+ cast<ObjCMethodDecl>(S.CurContext->getNonClosureAncestor());<br>
+ return S.LookupMethodInObjectType(sel,<br>
+ S.Context.getObjCInterfaceType(method->getClassInterface()),<br>
+ /*instance*/ false);<br>
+ }<br>
+<br>
return S.LookupMethodInObjectType(sel, PT->getPointeeType(), true);<br>
}<br>
<br>
@@ -59,281 +412,374 @@<br>
return S.LookupMethodInObjectType(sel, IT, false);<br>
}<br>
<br>
-ExprResult Sema::checkPseudoObjectRValue(Expr *E) {<br>
- assert(E->getValueKind() == VK_LValue &&<br>
- E->getObjectKind() == OK_ObjCProperty);<br>
- const ObjCPropertyRefExpr *PRE = E->getObjCProperty();<br>
-<br>
- QualType ReceiverType;<br>
- if (PRE->isObjectReceiver())<br>
- ReceiverType = PRE->getBase()->getType();<br>
- else if (PRE->isSuperReceiver())<br>
- ReceiverType = PRE->getSuperReceiverType();<br>
- else<br>
- ReceiverType = Context.getObjCInterfaceType(PRE->getClassReceiver());<br>
-<br>
- ExprValueKind VK = VK_RValue;<br>
- QualType T;<br>
- if (PRE->isImplicitProperty()) {<br>
- if (ObjCMethodDecl *GetterMethod =<br>
- PRE->getImplicitPropertyGetter()) {<br>
- T = getMessageSendResultType(ReceiverType, GetterMethod,<br>
- PRE->isClassReceiver(),<br>
- PRE->isSuperReceiver());<br>
- VK = Expr::getValueKindForType(GetterMethod->getResultType());<br>
- } else {<br>
- Diag(PRE->getLocation(), diag::err_getter_not_found)<br>
- << PRE->getBase()->getType();<br>
- return ExprError();<br>
- }<br>
- } else {<br>
- ObjCPropertyDecl *prop = PRE->getExplicitProperty();<br>
+bool ObjCPropertyOpBuilder::findGetter() {<br>
+ if (Getter) return true;<br>
+<br>
+ Getter = LookupMethodInReceiverType(S, RefExpr->getGetterSelector(), RefExpr);<br>
+ return (Getter != 0);<br>
+}<br>
<br>
- ObjCMethodDecl *getter =<br>
- LookupMethodInReceiverType(*this, prop->getGetterName(), PRE);<br>
- if (getter && !getter->hasRelatedResultType())<br>
- DiagnosePropertyAccessorMismatch(prop, getter, PRE->getLocation());<br>
- if (!getter) getter = prop->getGetterMethodDecl();<br>
-<br>
- // Figure out the type of the expression. Mostly this is the<br>
- // result type of the getter, if possible.<br>
- if (getter) {<br>
- T = getMessageSendResultType(ReceiverType, getter,<br>
- PRE->isClassReceiver(),<br>
- PRE->isSuperReceiver());<br>
- VK = Expr::getValueKindForType(getter->getResultType());<br>
-<br>
- // As a special case, if the method returns 'id', try to get a<br>
- // better type from the property.<br>
- if (VK == VK_RValue && T->isObjCIdType() &&<br>
- prop->getType()->isObjCRetainableType())<br>
- T = prop->getType();<br>
+/// Try to find the most accurate setter declaration for the property<br>
+/// reference.<br>
+///<br>
+/// \return true if a setter was found, in which case Setter<br>
+bool ObjCPropertyOpBuilder::findSetter() {<br>
+ // For implicit properties, just trust the lookup we already did.<br>
+ if (RefExpr->isImplicitProperty()) {<br>
+ if (ObjCMethodDecl *setter = RefExpr->getImplicitPropertySetter()) {<br>
+ Setter = setter;<br>
+ SetterSelector = setter->getSelector();<br>
+ return true;<br>
} else {<br>
- T = prop->getType();<br>
- VK = Expr::getValueKindForType(T);<br>
- T = T.getNonLValueExprType(Context);<br>
+ IdentifierInfo *getterName =<br>
+ RefExpr->getImplicitPropertyGetter()->getSelector()<br>
+ .getIdentifierInfoForSlot(0);<br>
+ SetterSelector =<br>
+ SelectorTable::constructSetterName(S.PP.getIdentifierTable(),<br>
+ S.PP.getSelectorTable(),<br>
+ getterName);<br>
+ return false;<br>
}<br>
}<br>
<br>
- E->setType(T);<br>
- E = ImplicitCastExpr::Create(Context, T, CK_GetObjCProperty, E, 0, VK);<br>
+ // For explicit properties, this is more involved.<br>
+ ObjCPropertyDecl *prop = RefExpr->getExplicitProperty();<br>
+ SetterSelector = prop->getSetterName();<br>
+<br>
+ // Do a normal method lookup first.<br>
+ if (ObjCMethodDecl *setter =<br>
+ LookupMethodInReceiverType(S, SetterSelector, RefExpr)) {<br>
+ Setter = setter;<br>
+ return true;<br>
+ }<br>
+<br>
+ // That can fail in the somewhat crazy situation that we're<br>
+ // type-checking a message send within the @interface declaration<br>
+ // that declared the @property. But it's not clear that that's<br>
+ // valuable to support.<br>
+<br>
+ return false;<br>
+}<br>
+<br>
+/// Capture the base object of an Objective-C property expression.<br>
+Expr *ObjCPropertyOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) {<br>
+ assert(InstanceReceiver == 0);<br>
+<br>
+ // If we have a base, capture it in an OVE and rebuild the syntactic<br>
+ // form to use the OVE as its base.<br>
+ if (RefExpr->isObjectReceiver()) {<br>
+ InstanceReceiver = capture(RefExpr->getBase());<br>
+<br>
+ syntacticBase =<br>
+ ObjCPropertyRefRebuilder(S, InstanceReceiver).rebuild(syntacticBase);<br>
+ }<br>
+<br>
+ return syntacticBase;<br>
+}<br>
+<br>
+/// Load from an Objective-C property reference.<br>
+ExprResult ObjCPropertyOpBuilder::buildGet() {<br>
+ findGetter();<br>
+ assert(Getter);<br>
<br>
- ExprResult Result = MaybeBindToTemporary(E);<br>
- if (!Result.isInvalid())<br>
- E = Result.take();<br>
+ QualType receiverType;<br>
+ SourceLocation superLoc;<br>
+ if (RefExpr->isClassReceiver()) {<br>
+ receiverType = S.Context.getObjCInterfaceType(RefExpr->getClassReceiver());<br>
+ } else if (RefExpr->isSuperReceiver()) {<br>
+ superLoc = RefExpr->getReceiverLocation();<br>
+ receiverType = RefExpr->getSuperReceiverType();<br>
+ } else {<br>
+ assert(InstanceReceiver);<br>
+ receiverType = InstanceReceiver->getType();<br>
+ }<br>
<br>
- return Owned(E);<br>
+ // Build a message-send.<br>
+ ExprResult msg;<br>
+ if (Getter->isInstanceMethod() || RefExpr->isObjectReceiver()) {<br>
+ assert(InstanceReceiver || RefExpr->isSuperReceiver());<br>
+ msg = S.BuildInstanceMessage(InstanceReceiver, receiverType, superLoc,<br>
+ Getter->getSelector(), Getter,<br>
+ GenericLoc, GenericLoc, GenericLoc,<br>
+ MultiExprArg());<br>
+ } else {<br>
+ TypeSourceInfo *receiverTypeInfo = 0;<br>
+ if (!RefExpr->isSuperReceiver())<br>
+ receiverTypeInfo = S.Context.getTrivialTypeSourceInfo(receiverType);<br>
+<br>
+ msg = S.BuildClassMessage(receiverTypeInfo, receiverType, superLoc,<br>
+ Getter->getSelector(), Getter,<br>
+ GenericLoc, GenericLoc, GenericLoc,<br>
+ MultiExprArg());<br>
+ }<br>
+ return msg;<br>
}<br>
<br>
-namespace {<br>
- struct PseudoObjectInfo {<br>
- const ObjCPropertyRefExpr *RefExpr;<br>
- bool HasSetter;<br>
- Selector SetterSelector;<br>
- ParmVarDecl *SetterParam;<br>
- QualType SetterParamType;<br>
+/// Store to an Objective-C property reference.<br>
+///<br>
+/// \param bindSetValueAsResult - If true, capture the actual<br>
+/// value being set as the value of the property operation.<br>
+ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc,<br>
+ bool captureSetValueAsResult) {<br>
+ bool hasSetter = findSetter();<br>
+ assert(hasSetter); (void) hasSetter;<br>
+<br>
+ QualType receiverType;<br>
+ SourceLocation superLoc;<br>
+ if (RefExpr->isClassReceiver()) {<br>
+ receiverType = S.Context.getObjCInterfaceType(RefExpr->getClassReceiver());<br>
+ } else if (RefExpr->isSuperReceiver()) {<br>
+ superLoc = RefExpr->getReceiverLocation();<br>
+ receiverType = RefExpr->getSuperReceiverType();<br>
+ } else {<br>
+ assert(InstanceReceiver);<br>
+ receiverType = InstanceReceiver->getType();<br>
+ }<br>
<br>
- void setSetter(ObjCMethodDecl *setter) {<br>
- HasSetter = true;<br>
- SetterParam = *setter->param_begin();<br>
- SetterParamType = SetterParam->getType().getUnqualifiedType();<br>
- }<br>
-<br>
- PseudoObjectInfo(Sema &S, Expr *E)<br>
- : RefExpr(E->getObjCProperty()), HasSetter(false), SetterParam(0) {<br>
-<br>
- assert(E->getValueKind() == VK_LValue &&<br>
- E->getObjectKind() == OK_ObjCProperty);<br>
-<br>
- // Try to find a setter.<br>
-<br>
- // For implicit properties, just trust the lookup we already did.<br>
- if (RefExpr->isImplicitProperty()) {<br>
- if (ObjCMethodDecl *setter = RefExpr->getImplicitPropertySetter()) {<br>
- setSetter(setter);<br>
- SetterSelector = setter->getSelector();<br>
- } else {<br>
- IdentifierInfo *getterName =<br>
- RefExpr->getImplicitPropertyGetter()->getSelector()<br>
- .getIdentifierInfoForSlot(0);<br>
- SetterSelector =<br>
- SelectorTable::constructSetterName(S.PP.getIdentifierTable(),<br>
- S.PP.getSelectorTable(),<br>
- getterName);<br>
- }<br>
- return;<br>
- }<br>
+ // Use assignment constraints when possible; they give us better<br>
+ // diagnostics. "When possible" basically means anything except a<br>
+ // C++ class type.<br>
+ if (!S.getLangOptions().CPlusPlus || !op->getType()->isRecordType()) {<br>
+ QualType paramType = (*Setter->param_begin())->getType();<br>
+ if (!S.getLangOptions().CPlusPlus || !paramType->isRecordType()) {<br>
+ ExprResult opResult = op;<br>
+ Sema::AssignConvertType assignResult<br>
+ = S.CheckSingleAssignmentConstraints(paramType, opResult);<br>
+ if (S.DiagnoseAssignmentResult(assignResult, opcLoc, paramType,<br>
+ op->getType(), opResult.get(),<br>
+ Sema::AA_Assigning))<br>
+ return ExprError();<br>
<br>
- // For explicit properties, this is more involved.<br>
- ObjCPropertyDecl *prop = RefExpr->getExplicitProperty();<br>
- SetterSelector = prop->getSetterName();<br>
-<br>
- // Do a normal method lookup first.<br>
- if (ObjCMethodDecl *setter =<br>
- LookupMethodInReceiverType(S, SetterSelector, RefExpr)) {<br>
- setSetter(setter);<br>
- return;<br>
- }<br>
+ op = opResult.take();<br>
+ assert(op && "successful assignment left argument invalid?");<br>
+ }<br>
+ }<br>
<br>
- // If that failed, trust the type on the @property declaration.<br>
- if (!prop->isReadOnly()) {<br>
- HasSetter = true;<br>
- SetterParamType = prop->getType().getUnqualifiedType();<br>
- }<br>
+ // Arguments.<br>
+ Expr *args[] = { op };<br>
+<br>
+ // Build a message-send.<br>
+ ExprResult msg;<br>
+ if (Setter->isInstanceMethod() || RefExpr->isObjectReceiver()) {<br>
+ msg = S.BuildInstanceMessage(InstanceReceiver, receiverType, superLoc,<br>
+ SetterSelector, Setter,<br>
+ GenericLoc, GenericLoc, GenericLoc,<br>
+ MultiExprArg(args, 1));<br>
+ } else {<br>
+ TypeSourceInfo *receiverTypeInfo = 0;<br>
+ if (!RefExpr->isSuperReceiver())<br>
+ receiverTypeInfo = S.Context.getTrivialTypeSourceInfo(receiverType);<br>
+<br>
+ msg = S.BuildClassMessage(receiverTypeInfo, receiverType, superLoc,<br>
+ SetterSelector, Setter,<br>
+ GenericLoc, GenericLoc, GenericLoc,<br>
+ MultiExprArg(args, 1));<br>
+ }<br>
+<br>
+ if (!msg.isInvalid() && captureSetValueAsResult) {<br>
+ ObjCMessageExpr *msgExpr =<br>
+ cast<ObjCMessageExpr>(msg.get()->IgnoreImplicit());<br>
+ Expr *arg = msgExpr->getArg(0);<br>
+ msgExpr->setArg(0, captureValueAsResult(arg));<br>
+ }<br>
+<br>
+ return msg;<br>
+}<br>
+<br>
+/// @property-specific behavior for doing lvalue-to-rvalue conversion.<br>
+ExprResult ObjCPropertyOpBuilder::buildRValueOperation(Expr *op) {<br>
+ // Explicit properties always have getters, but implicit ones don't.<br>
+ // Check that before proceeding.<br>
+ if (RefExpr->isImplicitProperty() &&<br>
+ !RefExpr->getImplicitPropertyGetter()) {<br>
+ S.Diag(RefExpr->getLocation(), diag::err_getter_not_found)<br>
+ << RefExpr->getBase()->getType();<br>
+ return ExprError();<br>
+ }<br>
+<br>
+ ExprResult result = PseudoOpBuilder::buildRValueOperation(op);<br>
+ if (result.isInvalid()) return ExprError();<br>
+<br>
+ if (RefExpr->isExplicitProperty() && !Getter->hasRelatedResultType())<br>
+ S.DiagnosePropertyAccessorMismatch(RefExpr->getExplicitProperty(),<br>
+ Getter, RefExpr->getLocation());<br>
+<br>
+ // As a special case, if the method returns 'id', try to get<br>
+ // a better type from the property.<br>
+ if (RefExpr->isExplicitProperty() && result.get()->isRValue() &&<br>
+ result.get()->getType()->isObjCIdType()) {<br>
+ QualType propType = RefExpr->getExplicitProperty()->getType();<br>
+ if (const ObjCObjectPointerType *ptr<br>
+ = propType->getAs<ObjCObjectPointerType>()) {<br>
+ if (!ptr->isObjCIdType())<br>
+ result = S.ImpCastExprToType(result.get(), propType, CK_BitCast);<br>
}<br>
- };<br>
+ }<br>
+<br>
+ return result;<br>
}<br>
<br>
-/// Check an increment or decrement of a pseudo-object expression.<br>
-ExprResult Sema::checkPseudoObjectIncDec(Scope *S, SourceLocation opcLoc,<br>
- UnaryOperatorKind opcode, Expr *op) {<br>
- assert(UnaryOperator::isIncrementDecrementOp(opcode));<br>
- PseudoObjectInfo info(*this, op);<br>
+/// Try to build this as a call to a getter that returns a reference.<br>
+///<br>
+/// \return true if it was possible, whether or not it actually<br>
+/// succeeded<br>
+bool ObjCPropertyOpBuilder::tryBuildGetOfReference(Expr *op,<br>
+ ExprResult &result) {<br>
+ if (!S.getLangOptions().CPlusPlus) return false;<br>
+<br>
+ findGetter();<br>
+ assert(Getter && "property has no setter and no getter!");<br>
+<br>
+ // Only do this if the getter returns an l-value reference type.<br>
+ QualType resultType = Getter->getResultType();<br>
+ if (!resultType->isLValueReferenceType()) return false;<br>
+<br>
+ result = buildRValueOperation(op);<br>
+ return true;<br>
+}<br>
+<br>
+/// @property-specific behavior for doing assignments.<br>
+ExprResult<br>
+ObjCPropertyOpBuilder::buildAssignmentOperation(Scope *Sc,<br>
+ SourceLocation opcLoc,<br>
+ BinaryOperatorKind opcode,<br>
+ Expr *LHS, Expr *RHS) {<br>
+ assert(BinaryOperator::isAssignmentOp(opcode));<br>
<br>
// If there's no setter, we have no choice but to try to assign to<br>
// the result of the getter.<br>
- if (!info.HasSetter) {<br>
- QualType resultType = info.RefExpr->getGetterResultType();<br>
- assert(!resultType.isNull() && "property has no setter and no getter!");<br>
-<br>
- // Only do this if the getter returns an l-value reference type.<br>
- if (const LValueReferenceType *refType<br>
- = resultType->getAs<LValueReferenceType>()) {<br>
- op = ImplicitCastExpr::Create(Context, refType->getPointeeType(),<br>
- CK_GetObjCProperty, op, 0, VK_LValue);<br>
- return BuildUnaryOp(S, opcLoc, opcode, op);<br>
+ if (!findSetter()) {<br>
+ ExprResult result;<br>
+ if (tryBuildGetOfReference(LHS, result)) {<br>
+ if (result.isInvalid()) return ExprError();<br>
+ return S.BuildBinOp(Sc, opcLoc, opcode, result.take(), RHS);<br>
}<br>
<br>
// Otherwise, it's an error.<br>
- Diag(opcLoc, diag::err_nosetter_property_incdec)<br>
- << unsigned(info.RefExpr->isImplicitProperty())<br>
- << unsigned(UnaryOperator::isDecrementOp(opcode))<br>
- << info.SetterSelector<br>
- << op->getSourceRange();<br>
+ S.Diag(opcLoc, diag::err_nosetter_property_assignment)<br>
+ << unsigned(RefExpr->isImplicitProperty())<br>
+ << SetterSelector<br>
+ << LHS->getSourceRange() << RHS->getSourceRange();<br>
return ExprError();<br>
}<br>
<br>
- // ++/-- behave like compound assignments, i.e. they need a getter.<br>
- QualType getterResultType = info.RefExpr->getGetterResultType();<br>
- if (getterResultType.isNull()) {<br>
- assert(info.RefExpr->isImplicitProperty());<br>
- Diag(opcLoc, diag::err_nogetter_property_incdec)<br>
- << unsigned(UnaryOperator::isDecrementOp(opcode))<br>
- << info.RefExpr->getImplicitPropertyGetter()->getSelector()<br>
- << op->getSourceRange();<br>
+ // If there is a setter, we definitely want to use it.<br>
+<br>
+ // Verify that we can do a compound assignment.<br>
+ if (opcode != BO_Assign && !findGetter()) {<br>
+ S.Diag(opcLoc, diag::err_nogetter_property_compound_assignment)<br>
+ << LHS->getSourceRange() << RHS->getSourceRange();<br>
return ExprError();<br>
}<br>
<br>
- // HACK: change the type of the operand to prevent further placeholder<br>
- // transformation.<br>
- op->setType(getterResultType.getNonLValueExprType(Context));<br>
- op->setObjectKind(OK_Ordinary);<br>
-<br>
- ExprResult result = CreateBuiltinUnaryOp(opcLoc, opcode, op);<br>
+ ExprResult result =<br>
+ PseudoOpBuilder::buildAssignmentOperation(Sc, opcLoc, opcode, LHS, RHS);<br>
if (result.isInvalid()) return ExprError();<br>
<br>
- // Change the object kind back.<br>
- op->setObjectKind(OK_ObjCProperty);<br>
+ // Various warnings about property assignments in ARC.<br>
+ if (S.getLangOptions().ObjCAutoRefCount && InstanceReceiver) {<br>
+ S.checkRetainCycles(InstanceReceiver->getSourceExpr(), RHS);<br>
+ S.checkUnsafeExprAssigns(opcLoc, LHS, RHS);<br>
+ }<br>
+<br>
return result;<br>
}<br>
<br>
-ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc,<br>
- BinaryOperatorKind opcode,<br>
- Expr *LHS, Expr *RHS) {<br>
- assert(BinaryOperator::isAssignmentOp(opcode));<br>
- PseudoObjectInfo info(*this, LHS);<br>
-<br>
+/// @property-specific behavior for doing increments and decrements.<br>
+ExprResult<br>
+ObjCPropertyOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc,<br>
+ UnaryOperatorKind opcode,<br>
+ Expr *op) {<br>
// If there's no setter, we have no choice but to try to assign to<br>
// the result of the getter.<br>
- if (!info.HasSetter) {<br>
- QualType resultType = info.RefExpr->getGetterResultType();<br>
- assert(!resultType.isNull() && "property has no setter and no getter!");<br>
-<br>
- // Only do this if the getter returns an l-value reference type.<br>
- if (const LValueReferenceType *refType<br>
- = resultType->getAs<LValueReferenceType>()) {<br>
- LHS = ImplicitCastExpr::Create(Context, refType->getPointeeType(),<br>
- CK_GetObjCProperty, LHS, 0, VK_LValue);<br>
- return BuildBinOp(S, opcLoc, opcode, LHS, RHS);<br>
+ if (!findSetter()) {<br>
+ ExprResult result;<br>
+ if (tryBuildGetOfReference(op, result)) {<br>
+ if (result.isInvalid()) return ExprError();<br>
+ return S.BuildUnaryOp(Sc, opcLoc, opcode, result.take());<br>
}<br>
<br>
// Otherwise, it's an error.<br>
- Diag(opcLoc, diag::err_nosetter_property_assignment)<br>
- << unsigned(info.RefExpr->isImplicitProperty())<br>
- << info.SetterSelector<br>
- << LHS->getSourceRange() << RHS->getSourceRange();<br>
+ S.Diag(opcLoc, diag::err_nosetter_property_incdec)<br>
+ << unsigned(RefExpr->isImplicitProperty())<br>
+ << unsigned(UnaryOperator::isDecrementOp(opcode))<br>
+ << SetterSelector<br>
+ << op->getSourceRange();<br>
return ExprError();<br>
}<br>
<br>
// If there is a setter, we definitely want to use it.<br>
<br>
- // If this is a simple assignment, just initialize the parameter<br>
- // with the RHS.<br>
- if (opcode == BO_Assign) {<br>
- LHS->setType(info.SetterParamType.getNonLValueExprType(Context));<br>
+ // We also need a getter.<br>
+ if (!findGetter()) {<br>
+ assert(RefExpr->isImplicitProperty());<br>
+ S.Diag(opcLoc, diag::err_nogetter_property_incdec)<br>
+ << unsigned(UnaryOperator::isDecrementOp(opcode))<br>
+ << RefExpr->getImplicitPropertyGetter()->getSelector() // FIXME!<br>
+ << op->getSourceRange();<br>
+ return ExprError();<br>
+ }<br>
<br>
- // Under certain circumstances, we need to type-check the RHS as a<br>
- // straight-up parameter initialization. This gives somewhat<br>
- // inferior diagnostics, so we try to avoid it.<br>
-<br>
- if (RHS->isTypeDependent()) {<br>
- // Just build the expression.<br>
-<br>
- } else if ((getLangOptions().CPlusPlus && LHS->getType()->isRecordType()) ||<br>
- (getLangOptions().ObjCAutoRefCount &&<br>
- info.SetterParam &&<br>
- info.SetterParam->hasAttr<NSConsumedAttr>())) {<br>
- InitializedEntity param = (info.SetterParam<br>
- ? InitializedEntity::InitializeParameter(Context, info.SetterParam)<br>
- : InitializedEntity::InitializeParameter(Context, info.SetterParamType,<br>
- /*consumed*/ false));<br>
- ExprResult arg = PerformCopyInitialization(param, opcLoc, RHS);<br>
- if (arg.isInvalid()) return ExprError();<br>
- RHS = arg.take();<br>
-<br>
- // Warn about assignments of +1 objects to unsafe pointers in ARC.<br>
- // CheckAssignmentOperands does this on the other path.<br>
- if (getLangOptions().ObjCAutoRefCount)<br>
- checkUnsafeExprAssigns(opcLoc, LHS, RHS);<br>
- } else {<br>
- ExprResult RHSResult = Owned(RHS);<br>
+ return PseudoOpBuilder::buildIncDecOperation(Sc, opcLoc, opcode, op);<br>
+}<br>
<br>
- LHS->setObjectKind(OK_Ordinary);<br>
- QualType resultType = CheckAssignmentOperands(LHS, RHSResult, opcLoc,<br>
- /*compound*/ QualType());<br>
- LHS->setObjectKind(OK_ObjCProperty);<br>
+//===----------------------------------------------------------------------===//<br>
+// General Sema routines.<br>
+//===----------------------------------------------------------------------===//<br>
<br>
- if (!RHSResult.isInvalid()) RHS = RHSResult.take();<br>
- if (resultType.isNull()) return ExprError();<br>
- }<br>
+ExprResult Sema::checkPseudoObjectRValue(Expr *E) {<br>
+ Expr *opaqueRef = E->IgnoreParens();<br>
+ if (ObjCPropertyRefExpr *refExpr<br>
+ = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) {<br>
+ ObjCPropertyOpBuilder builder(*this, refExpr);<br>
+ return builder.buildRValueOperation(E);<br>
+ } else {<br>
+ llvm_unreachable("unknown pseudo-object kind!");<br>
+ }<br>
+}<br>
<br>
- // Warn about property sets in ARC that might cause retain cycles.<br>
- if (getLangOptions().ObjCAutoRefCount && !info.RefExpr->isSuperReceiver())<br>
- checkRetainCycles(const_cast<Expr*>(info.RefExpr->getBase()), RHS);<br>
+/// Check an increment or decrement of a pseudo-object expression.<br>
+ExprResult Sema::checkPseudoObjectIncDec(Scope *Sc, SourceLocation opcLoc,<br>
+ UnaryOperatorKind opcode, Expr *op) {<br>
+ // Do nothing if the operand is dependent.<br>
+ if (op->isTypeDependent())<br>
+ return new (Context) UnaryOperator(op, opcode, Context.DependentTy,<br>
+ VK_RValue, OK_Ordinary, opcLoc);<br>
<br>
- return new (Context) BinaryOperator(LHS, RHS, opcode, RHS->getType(),<br>
- RHS->getValueKind(),<br>
- RHS->getObjectKind(),<br>
- opcLoc);<br>
+ assert(UnaryOperator::isIncrementDecrementOp(opcode));<br>
+ Expr *opaqueRef = op->IgnoreParens();<br>
+ if (ObjCPropertyRefExpr *refExpr<br>
+ = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) {<br>
+ ObjCPropertyOpBuilder builder(*this, refExpr);<br>
+ return builder.buildIncDecOperation(Sc, opcLoc, opcode, op);<br>
+ } else {<br>
+ llvm_unreachable("unknown pseudo-object kind!");<br>
}<br>
+}<br>
<br>
- // If this is a compound assignment, we need to use the getter, too.<br>
- QualType getterResultType = info.RefExpr->getGetterResultType();<br>
- if (getterResultType.isNull()) {<br>
- Diag(opcLoc, diag::err_nogetter_property_compound_assignment)<br>
- << LHS->getSourceRange() << RHS->getSourceRange();<br>
- return ExprError();<br>
+ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc,<br>
+ BinaryOperatorKind opcode,<br>
+ Expr *LHS, Expr *RHS) {<br>
+ // Do nothing if either argument is dependent.<br>
+ if (LHS->isTypeDependent() || RHS->isTypeDependent())<br>
+ return new (Context) BinaryOperator(LHS, RHS, opcode, Context.DependentTy,<br>
+ VK_RValue, OK_Ordinary, opcLoc);<br>
+<br>
+ // Filter out non-overload placeholder types in the RHS.<br>
+ if (const BuiltinType *PTy = RHS->getType()->getAsPlaceholderType()) {<br>
+ if (PTy->getKind() != BuiltinType::Overload) {<br>
+ ExprResult result = CheckPlaceholderExpr(RHS);<br>
+ if (result.isInvalid()) return ExprError();<br>
+ RHS = result.take();<br>
+ }<br>
}<br>
<br>
- // HACK: change the type of the LHS to prevent further placeholder<br>
- // transformation.<br>
- LHS->setType(getterResultType.getNonLValueExprType(Context));<br>
- LHS->setObjectKind(OK_Ordinary);<br>
-<br>
- ExprResult result = CreateBuiltinBinOp(opcLoc, opcode, LHS, RHS);<br>
- if (result.isInvalid()) return ExprError();<br>
-<br>
- // Change the object kind back.<br>
- LHS->setObjectKind(OK_ObjCProperty);<br>
- return result;<br>
+ Expr *opaqueRef = LHS->IgnoreParens();<br>
+ if (ObjCPropertyRefExpr *refExpr<br>
+ = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) {<br>
+ ObjCPropertyOpBuilder builder(*this, refExpr);<br>
+ return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS);<br>
+ } else {<br>
+ llvm_unreachable("unknown pseudo-object kind!");<br>
+ }<br>
}<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaStmt.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Sun Nov 6 03:01:30 2011<br>
@@ -198,7 +198,7 @@<br>
Diag(Loc, diag::warn_unused_result) << R1 << R2;<br>
return;<br>
}<br>
- } else if (isa<ObjCPropertyRefExpr>(E)) {<br>
+ } else if (isa<PseudoObjectExpr>(E)) {<br>
DiagID = diag::warn_unused_property_expr;<br>
} else if (const CXXFunctionalCastExpr *FC<br>
= dyn_cast<CXXFunctionalCastExpr>(E)) {<br>
<br>
Modified: cfe/trunk/lib/Sema/TreeTransform.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/TreeTransform.h (original)<br>
+++ cfe/trunk/lib/Sema/TreeTransform.h Sun Nov 6 03:01:30 2011<br>
@@ -6103,6 +6103,22 @@<br>
<br>
template<typename Derived><br>
ExprResult<br>
+TreeTransform<Derived>::TransformPseudoObjectExpr(PseudoObjectExpr *E) {<br>
+ // Rebuild the syntactic form.<br>
+ ExprResult result = getDerived().TransformExpr(E->getSyntacticForm());<br>
+ if (result.isInvalid()) return ExprError();<br>
+<br>
+ // If that gives us a pseudo-object result back, the pseudo-object<br>
+ // expression must have been an lvalue-to-rvalue conversion which we<br>
+ // should reapply.<br>
+ if (result.get()->hasPlaceholderType(BuiltinType::PseudoObject))<br>
+ result = SemaRef.checkPseudoObjectRValue(result.take());<br>
+<br>
+ return result;<br>
+}<br>
+<br>
+template<typename Derived><br>
+ExprResult<br>
TreeTransform<Derived>::TransformUnaryExprOrTypeTraitExpr(<br>
UnaryExprOrTypeTraitExpr *E) {<br>
if (E->isArgumentType()) {<br>
<br>
Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original)<br>
+++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Sun Nov 6 03:01:30 2011<br>
@@ -775,6 +775,24 @@<br>
E->RParenLoc = ReadSourceLocation(Record, Idx);<br>
}<br>
<br>
+void ASTStmtReader::VisitPseudoObjectExpr(PseudoObjectExpr *E) {<br>
+ VisitExpr(E);<br>
+ unsigned numSemanticExprs = Record[Idx++];<br>
+ assert(numSemanticExprs + 1 == E->PseudoObjectExprBits.NumSubExprs);<br>
+ E->PseudoObjectExprBits.ResultIndex = Record[Idx++];<br>
+<br>
+ // Read the syntactic expression.<br>
+ E->getSubExprsBuffer()[0] = Reader.ReadSubExpr();<br>
+<br>
+ // Read all the semantic expressions.<br>
+ for (unsigned i = 0; i != numSemanticExprs; ++i) {<br>
+ Expr *subExpr = Reader.ReadSubExpr();<br>
+ if (isa<OpaqueValueExpr>(subExpr))<br>
+ cast<OpaqueValueExpr>(subExpr)->setSourceExpr(Reader.ReadSubExpr());<br>
+ E->getSubExprsBuffer()[i+1] = subExpr;<br>
+ }<br>
+}<br>
+<br>
void ASTStmtReader::VisitAtomicExpr(AtomicExpr *E) {<br>
VisitExpr(E);<br>
E->setOp(AtomicExpr::AtomicOp(Record[Idx++]));<br>
@@ -2059,6 +2077,12 @@<br>
S = new (Context) AsTypeExpr(Empty);<br>
break;<br>
<br>
+ case EXPR_PSEUDO_OBJECT: {<br>
+ unsigned numSemanticExprs = Record[ASTStmtReader::NumExprFields];<br>
+ S = PseudoObjectExpr::Create(Context, Empty, numSemanticExprs);<br>
+ break;<br>
+ }<br>
+<br>
case EXPR_ATOMIC:<br>
S = new (Context) AtomicExpr(Empty);<br>
break;<br>
<br>
Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original)<br>
+++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Sun Nov 6 03:01:30 2011<br>
@@ -736,6 +736,25 @@<br>
Code = serialization::EXPR_GENERIC_SELECTION;<br>
}<br>
<br>
+void ASTStmtWriter::VisitPseudoObjectExpr(PseudoObjectExpr *E) {<br>
+ VisitExpr(E);<br>
+ Record.push_back(E->getNumSemanticExprs());<br>
+<br>
+ // Push the result index. Currently, this needs to exactly match<br>
+ // the encoding used internally for ResultIndex.<br>
+ unsigned result = E->getResultExprIndex();<br>
+ result = (result == PseudoObjectExpr::NoResult ? 0 : result + 1);<br>
+ Record.push_back(result);<br>
+<br>
+ Writer.AddStmt(E->getSyntacticForm());<br>
+ for (PseudoObjectExpr::semantics_iterator<br>
+ i = E->semantics_begin(), e = E->semantics_end(); i != e; ++i) {<br>
+ Writer.AddStmt(*i);<br>
+ if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(*i))<br>
+ Writer.AddStmt(OVE->getSourceExpr());<br>
+ }<br>
+}<br>
+<br>
void ASTStmtWriter::VisitAtomicExpr(AtomicExpr *E) {<br>
VisitExpr(E);<br>
Record.push_back(E->getOp());<br>
<br>
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)<br>
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Sun Nov 6 03:01:30 2011<br>
@@ -857,6 +857,21 @@<br>
Bldr.addNodes(Dst);<br>
break;<br>
}<br>
+<br>
+ case Stmt::PseudoObjectExprClass: {<br>
+ Bldr.takeNodes(Pred);<br>
+ const ProgramState *state = Pred->getState();<br>
+ const PseudoObjectExpr *PE = cast<PseudoObjectExpr>(S);<br>
+ if (const Expr *Result = PE->getResultExpr()) {<br>
+ SVal V = state->getSVal(Result);<br>
+ Bldr.generateNode(S, Pred, state->BindExpr(S, V));<br>
+ }<br>
+ else<br>
+ Bldr.generateNode(S, Pred, state->BindExpr(S, UnknownVal()));<br>
+<br>
+ Bldr.addNodes(Dst);<br>
+ break;<br>
+ }<br>
}<br>
}<br>
<br>
<br>
Modified: cfe/trunk/test/Analysis/casts.m<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/casts.m?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/casts.m?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/Analysis/casts.m (original)<br>
+++ cfe/trunk/test/Analysis/casts.m Sun Nov 6 03:01:30 2011<br>
@@ -33,9 +33,10 @@<br>
RDR10087620Enum elem;<br>
}<br>
@property (readwrite, nonatomic) RDR10087620Enum elem;<br>
+@end<br>
+<br>
static void<br>
adium_media_ready_cb(RDR10087620 *InObj)<br>
{<br>
InObj.elem |= EEOne;<br>
}<br>
-@end<br>
\ No newline at end of file<br>
<br>
Modified: cfe/trunk/test/Analysis/retain-release-path-notes.m<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/retain-release-path-notes.m?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/retain-release-path-notes.m?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/Analysis/retain-release-path-notes.m (original)<br>
+++ cfe/trunk/test/Analysis/retain-release-path-notes.m Sun Nov 6 03:01:30 2011<br>
@@ -1,5 +1,10 @@<br>
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -analyzer-output=text -verify %s<br>
<br>
+// This actually still works after the pseudo-object refactor, it just<br>
+// uses messages that say 'method' instead of 'property'. Ted wanted<br>
+// this xfailed and filed as a bug. rdar://problem/10402993<br>
+// XFAIL: *<br>
+<br>
/***<br>
This file is for testing the path-sensitive notes for retain/release errors.<br>
Its goal is to have simple branch coverage of any path-based diagnostics,<br>
<br>
Modified: cfe/trunk/tools/libclang/CIndex.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/tools/libclang/CIndex.cpp (original)<br>
+++ cfe/trunk/tools/libclang/CIndex.cpp Sun Nov 6 03:01:30 2011<br>
@@ -1714,6 +1714,8 @@<br>
void VisitUnresolvedMemberExpr(UnresolvedMemberExpr *U);<br>
void VisitVAArgExpr(VAArgExpr *E);<br>
void VisitSizeOfPackExpr(SizeOfPackExpr *E);<br>
+ void VisitPseudoObjectExpr(PseudoObjectExpr *E);<br>
+ void VisitOpaqueValueExpr(OpaqueValueExpr *E);<br>
<br>
private:<br>
void AddDeclarationNameInfo(Stmt *S);<br>
@@ -2022,6 +2024,17 @@<br>
void EnqueueVisitor::VisitSizeOfPackExpr(SizeOfPackExpr *E) {<br>
WL.push_back(SizeOfPackExprParts(E, Parent));<br>
}<br>
+void EnqueueVisitor::VisitOpaqueValueExpr(OpaqueValueExpr *E) {<br>
+ // If the opaque value has a source expression, just transparently<br>
+ // visit that. This is useful for (e.g.) pseudo-object expressions.<br>
+ if (Expr *SourceExpr = E->getSourceExpr())<br>
+ return Visit(SourceExpr);<br>
+ AddStmt(E);<br>
+}<br>
+void EnqueueVisitor::VisitPseudoObjectExpr(PseudoObjectExpr *E) {<br>
+ // Treat the expression like its syntactic form.<br>
+ Visit(E->getSyntacticForm());<br>
+}<br>
<br>
void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, Stmt *S) {<br>
EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU,RegionOfInterest)).Visit(S);<br>
@@ -2702,6 +2715,11 @@<br>
return RE->getDecl();<br>
if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(E))<br>
return PRE->isExplicitProperty() ? PRE->getExplicitProperty() : 0;<br>
+ if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E))<br>
+ return getDeclFromExpr(POE->getSyntacticForm());<br>
+ if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E))<br>
+ if (Expr *Src = OVE->getSourceExpr())<br>
+ return getDeclFromExpr(Src);<br>
<br>
if (CallExpr *CE = dyn_cast<CallExpr>(E))<br>
return getDeclFromExpr(CE->getCallee());<br>
<br>
Modified: cfe/trunk/tools/libclang/CXCursor.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXCursor.cpp?rev=143867&r1=143866&r2=143867&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXCursor.cpp?rev=143867&r1=143866&r2=143867&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/tools/libclang/CXCursor.cpp (original)<br>
+++ cfe/trunk/tools/libclang/CXCursor.cpp Sun Nov 6 03:01:30 2011<br>
@@ -219,7 +219,6 @@<br>
case Stmt::MaterializeTemporaryExprClass:<br>
case Stmt::ObjCIndirectCopyRestoreExprClass:<br>
case Stmt::OffsetOfExprClass:<br>
- case Stmt::OpaqueValueExprClass:<br>
case Stmt::ParenListExprClass:<br>
case Stmt::PredefinedExprClass:<br>
case Stmt::ShuffleVectorExprClass:<br>
@@ -229,6 +228,16 @@<br>
K = CXCursor_UnexposedExpr;<br>
break;<br>
<br>
+ case Stmt::OpaqueValueExprClass:<br>
+ if (Expr *Src = cast<OpaqueValueExpr>(S)->getSourceExpr())<br>
+ return MakeCXCursor(Src, Parent, TU, RegionOfInterest);<br>
+ K = CXCursor_UnexposedExpr;<br>
+ break;<br>
+<br>
+ case Stmt::PseudoObjectExprClass:<br>
+ return MakeCXCursor(cast<PseudoObjectExpr>(S)->getSyntacticForm(),<br>
+ Parent, TU, RegionOfInterest);<br>
+<br>
case Stmt::CompoundStmtClass:<br>
K = CXCursor_CompoundStmt;<br>
break;<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>