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