Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit 4b9c2d2

Browse files
committed
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@143867 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent a463089 commit 4b9c2d2

40 files changed

+1674
-652
lines changed

Diff for: include/clang/AST/DeclBase.h

+8
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,14 @@ class DeclContext {
974974
/// declaration context DC.
975975
bool Encloses(const DeclContext *DC) const;
976976

977+
/// \brief Find the nearest non-closure ancestor of this context,
978+
/// i.e. the innermost semantic parent of this context which is not
979+
/// a closure. A context may be its own non-closure ancestor.
980+
DeclContext *getNonClosureAncestor();
981+
const DeclContext *getNonClosureAncestor() const {
982+
return const_cast<DeclContext*>(this)->getNonClosureAncestor();
983+
}
984+
977985
/// getPrimaryContext - There may be many different
978986
/// declarations of the same entity (including forward declarations
979987
/// of classes, multiple definitions of namespaces, etc.), each with

Diff for: include/clang/AST/Expr.h

+141
Original file line numberDiff line numberDiff line change
@@ -2758,6 +2758,13 @@ class BinaryOperator : public Expr {
27582758
bool isCompoundAssignmentOp() const {
27592759
return isCompoundAssignmentOp(getOpcode());
27602760
}
2761+
static Opcode getOpForCompoundAssignment(Opcode Opc) {
2762+
assert(isCompoundAssignmentOp(Opc));
2763+
if (Opc >= BO_XorAssign)
2764+
return Opcode(unsigned(Opc) - BO_XorAssign + BO_Xor);
2765+
else
2766+
return Opcode(unsigned(Opc) - BO_MulAssign + BO_Mul);
2767+
}
27612768

27622769
static bool isShiftAssignOp(Opcode Opc) {
27632770
return Opc == BO_ShlAssign || Opc == BO_ShrAssign;
@@ -4251,6 +4258,140 @@ class AsTypeExpr : public Expr { // Should this be an ExplicitCastExpr?
42514258
child_range children() { return child_range(&SrcExpr, &SrcExpr+1); }
42524259
};
42534260

4261+
/// PseudoObjectExpr - An expression which accesses a pseudo-object
4262+
/// l-value. A pseudo-object is an abstract object, accesses to which
4263+
/// are translated to calls. The pseudo-object expression has a
4264+
/// syntactic form, which shows how the expression was actually
4265+
/// written in the source code, and a semantic form, which is a series
4266+
/// of expressions to be executed in order which detail how the
4267+
/// operation is actually evaluated. Optionally, one of the semantic
4268+
/// forms may also provide a result value for the expression.
4269+
///
4270+
/// If any of the semantic-form expressions is an OpaqueValueExpr,
4271+
/// that OVE is required to have a source expression, and it is bound
4272+
/// to the result of that source expression. Such OVEs may appear
4273+
/// only in subsequent semantic-form expressions and as
4274+
/// sub-expressions of the syntactic form.
4275+
///
4276+
/// PseudoObjectExpr should be used only when an operation can be
4277+
/// usefully described in terms of fairly simple rewrite rules on
4278+
/// objects and functions that are meant to be used by end-developers.
4279+
/// For example, under the Itanium ABI, dynamic casts are implemented
4280+
/// as a call to a runtime function called __dynamic_cast; using this
4281+
/// class to describe that would be inappropriate because that call is
4282+
/// not really part of the user-visible semantics, and instead the
4283+
/// cast is properly reflected in the AST and IR-generation has been
4284+
/// taught to generate the call as necessary. In contrast, an
4285+
/// Objective-C property access is semantically defined to be
4286+
/// equivalent to a particular message send, and this is very much
4287+
/// part of the user model. The name of this class encourages this
4288+
/// modelling design.
4289+
class PseudoObjectExpr : public Expr {
4290+
// PseudoObjectExprBits.NumSubExprs - The number of sub-expressions.
4291+
// Always at least two, because the first sub-expression is the
4292+
// syntactic form.
4293+
4294+
// PseudoObjectExprBits.ResultIndex - The index of the
4295+
// sub-expression holding the result. 0 means the result is void,
4296+
// which is unambiguous because it's the index of the syntactic
4297+
// form. Note that this is therefore 1 higher than the value passed
4298+
// in to Create, which is an index within the semantic forms.
4299+
// Note also that ASTStmtWriter assumes this encoding.
4300+
4301+
Expr **getSubExprsBuffer() { return reinterpret_cast<Expr**>(this + 1); }
4302+
const Expr * const *getSubExprsBuffer() const {
4303+
return reinterpret_cast<const Expr * const *>(this + 1);
4304+
}
4305+
4306+
friend class ASTStmtReader;
4307+
4308+
PseudoObjectExpr(QualType type, ExprValueKind VK,
4309+
Expr *syntactic, ArrayRef<Expr*> semantic,
4310+
unsigned resultIndex);
4311+
4312+
PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs);
4313+
4314+
unsigned getNumSubExprs() const {
4315+
return PseudoObjectExprBits.NumSubExprs;
4316+
}
4317+
4318+
public:
4319+
/// NoResult - A value for the result index indicating that there is
4320+
/// no semantic result.
4321+
enum { NoResult = ~0U };
4322+
4323+
static PseudoObjectExpr *Create(ASTContext &Context, Expr *syntactic,
4324+
ArrayRef<Expr*> semantic,
4325+
unsigned resultIndex);
4326+
4327+
static PseudoObjectExpr *Create(ASTContext &Context, EmptyShell shell,
4328+
unsigned numSemanticExprs);
4329+
4330+
/// Return the syntactic form of this expression, i.e. the
4331+
/// expression it actually looks like. Likely to be expressed in
4332+
/// terms of OpaqueValueExprs bound in the semantic form.
4333+
Expr *getSyntacticForm() { return getSubExprsBuffer()[0]; }
4334+
const Expr *getSyntacticForm() const { return getSubExprsBuffer()[0]; }
4335+
4336+
/// Return the index of the result-bearing expression into the semantics
4337+
/// expressions, or PseudoObjectExpr::NoResult if there is none.
4338+
unsigned getResultExprIndex() const {
4339+
if (PseudoObjectExprBits.ResultIndex == 0) return NoResult;
4340+
return PseudoObjectExprBits.ResultIndex - 1;
4341+
}
4342+
4343+
/// Return the result-bearing expression, or null if there is none.
4344+
Expr *getResultExpr() {
4345+
if (PseudoObjectExprBits.ResultIndex == 0)
4346+
return 0;
4347+
return getSubExprsBuffer()[PseudoObjectExprBits.ResultIndex];
4348+
}
4349+
const Expr *getResultExpr() const {
4350+
return const_cast<PseudoObjectExpr*>(this)->getResultExpr();
4351+
}
4352+
4353+
unsigned getNumSemanticExprs() const { return getNumSubExprs() - 1; }
4354+
4355+
typedef Expr * const *semantics_iterator;
4356+
typedef const Expr * const *const_semantics_iterator;
4357+
semantics_iterator semantics_begin() {
4358+
return getSubExprsBuffer() + 1;
4359+
}
4360+
const_semantics_iterator semantics_begin() const {
4361+
return getSubExprsBuffer() + 1;
4362+
}
4363+
semantics_iterator semantics_end() {
4364+
return getSubExprsBuffer() + getNumSubExprs();
4365+
}
4366+
const_semantics_iterator semantics_end() const {
4367+
return getSubExprsBuffer() + getNumSubExprs();
4368+
}
4369+
Expr *getSemanticExpr(unsigned index) {
4370+
assert(index + 1 < getNumSubExprs());
4371+
return getSubExprsBuffer()[index + 1];
4372+
}
4373+
const Expr *getSemanticExpr(unsigned index) const {
4374+
return const_cast<PseudoObjectExpr*>(this)->getSemanticExpr(index);
4375+
}
4376+
4377+
SourceLocation getExprLoc() const {
4378+
return getSyntacticForm()->getExprLoc();
4379+
}
4380+
SourceRange getSourceRange() const {
4381+
return getSyntacticForm()->getSourceRange();
4382+
}
4383+
4384+
child_range children() {
4385+
Stmt **cs = reinterpret_cast<Stmt**>(getSubExprsBuffer());
4386+
return child_range(cs, cs + getNumSubExprs());
4387+
}
4388+
4389+
static bool classof(const Stmt *T) {
4390+
return T->getStmtClass() == PseudoObjectExprClass;
4391+
}
4392+
static bool classof(const PseudoObjectExpr *) { return true; }
4393+
};
4394+
42544395
/// AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*,
42554396
/// __atomic_load, __atomic_store, and __atomic_compare_exchange_*, for the
42564397
/// similarly-named C++0x instructions. All of these instructions take one

Diff for: include/clang/AST/RecursiveASTVisitor.h

+17
Original file line numberDiff line numberDiff line change
@@ -1874,6 +1874,23 @@ TraverseGenericSelectionExpr(GenericSelectionExpr *S) {
18741874
return true;
18751875
}
18761876

1877+
// PseudoObjectExpr is a special case because of the wierdness with
1878+
// syntactic expressions and opaque values.
1879+
template<typename Derived>
1880+
bool RecursiveASTVisitor<Derived>::
1881+
TraversePseudoObjectExpr(PseudoObjectExpr *S) {
1882+
TRY_TO(WalkUpFromPseudoObjectExpr(S));
1883+
TRY_TO(TraverseStmt(S->getSyntacticForm()));
1884+
for (PseudoObjectExpr::semantics_iterator
1885+
i = S->semantics_begin(), e = S->semantics_end(); i != e; ++i) {
1886+
Expr *sub = *i;
1887+
if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(sub))
1888+
sub = OVE->getSourceExpr();
1889+
TRY_TO(TraverseStmt(sub));
1890+
}
1891+
return true;
1892+
}
1893+
18771894
DEF_TRAVERSE_STMT(CXXScalarValueInitExpr, {
18781895
// This is called for code like 'return T()' where T is a built-in
18791896
// (i.e. non-class) type.

Diff for: include/clang/AST/Stmt.h

+14
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ class Stmt {
146146
friend class CXXUnresolvedConstructExpr; // ctor
147147
friend class CXXDependentScopeMemberExpr; // ctor
148148
friend class OverloadExpr; // ctor
149+
friend class PseudoObjectExpr; // ctor
149150
friend class AtomicExpr; // ctor
150151
unsigned : NumStmtBits;
151152

@@ -184,6 +185,18 @@ class Stmt {
184185
unsigned NumPreArgs : 1;
185186
};
186187

188+
class PseudoObjectExprBitfields {
189+
friend class PseudoObjectExpr;
190+
friend class ASTStmtReader; // deserialization
191+
192+
unsigned : NumExprBits;
193+
194+
// These don't need to be particularly wide, because they're
195+
// strictly limited by the forms of expressions we permit.
196+
unsigned NumSubExprs : 8;
197+
unsigned ResultIndex : 32 - 8 - NumExprBits;
198+
};
199+
187200
class ObjCIndirectCopyRestoreExprBitfields {
188201
friend class ObjCIndirectCopyRestoreExpr;
189202
unsigned : NumExprBits;
@@ -201,6 +214,7 @@ class Stmt {
201214
DeclRefExprBitfields DeclRefExprBits;
202215
CastExprBitfields CastExprBits;
203216
CallExprBitfields CallExprBits;
217+
PseudoObjectExprBitfields PseudoObjectExprBits;
204218
ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits;
205219
};
206220

Diff for: include/clang/Basic/StmtNodes.td

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ def ImplicitValueInitExpr : DStmt<Expr>;
7777
def ParenListExpr : DStmt<Expr>;
7878
def VAArgExpr : DStmt<Expr>;
7979
def GenericSelectionExpr : DStmt<Expr>;
80+
def PseudoObjectExpr : DStmt<Expr>;
8081

8182
// Atomic expressions
8283
def AtomicExpr : DStmt<Expr>;

Diff for: include/clang/Serialization/ASTBitCodes.h

+2
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,8 @@ namespace clang {
10001000
EXPR_BLOCK_DECL_REF,
10011001
/// \brief A GenericSelectionExpr record.
10021002
EXPR_GENERIC_SELECTION,
1003+
/// \brief A PseudoObjectExpr record.
1004+
EXPR_PSEUDO_OBJECT,
10031005
/// \brief An AtomicExpr record.
10041006
EXPR_ATOMIC,
10051007

Diff for: lib/ARCMigrate/TransRetainReleaseDealloc.cpp

+5-3
Original file line numberDiff line numberDiff line change
@@ -160,12 +160,14 @@ class RetainReleaseDeallocRemover :
160160
if (!E) return false;
161161

162162
E = E->IgnoreParenCasts();
163+
164+
// Also look through property-getter sugar.
165+
if (PseudoObjectExpr *pseudoOp = dyn_cast<PseudoObjectExpr>(E))
166+
E = pseudoOp->getResultExpr()->IgnoreImplicit();
167+
163168
if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
164169
return (ME->isInstanceMessage() && ME->getSelector() == DelegateSel);
165170

166-
if (ObjCPropertyRefExpr *propE = dyn_cast<ObjCPropertyRefExpr>(E))
167-
return propE->getGetterSelector() == DelegateSel;
168-
169171
return false;
170172
}
171173

Diff for: lib/ARCMigrate/TransUnbridgedCasts.cpp

+9-1
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,15 @@ class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
236236
}
237237
}
238238

239-
if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getSubExpr())){
239+
Expr *subExpr = E->getSubExpr();
240+
241+
// Look through pseudo-object expressions.
242+
if (PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(subExpr)) {
243+
subExpr = pseudo->getResultExpr();
244+
assert(subExpr && "no result for pseudo-object of non-void type?");
245+
}
246+
247+
if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(subExpr)) {
240248
if (implCE->getCastKind() == CK_ARCConsumeObject)
241249
return rewriteToBridgedCast(E, OBC_BridgeRetained);
242250
if (implCE->getCastKind() == CK_ARCReclaimReturnedObject)

Diff for: lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp

+45-19
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,15 @@ class ZeroOutInDeallocRemover :
7878
return true;
7979
}
8080

81+
bool VisitPseudoObjectExpr(PseudoObjectExpr *POE) {
82+
if (isZeroingPropIvar(POE) && isRemovable(POE)) {
83+
Transaction Trans(Pass.TA);
84+
Pass.TA.removeStmt(POE);
85+
}
86+
87+
return true;
88+
}
89+
8190
bool VisitBinaryOperator(BinaryOperator *BOE) {
8291
if (isZeroingPropIvar(BOE) && isRemovable(BOE)) {
8392
Transaction Trans(Pass.TA);
@@ -142,17 +151,21 @@ class ZeroOutInDeallocRemover :
142151
}
143152

144153
bool isZeroingPropIvar(Expr *E) {
145-
BinaryOperator *BOE = dyn_cast_or_null<BinaryOperator>(E);
146-
if (!BOE) return false;
154+
E = E->IgnoreParens();
155+
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E))
156+
return isZeroingPropIvar(BO);
157+
if (PseudoObjectExpr *PO = dyn_cast<PseudoObjectExpr>(E))
158+
return isZeroingPropIvar(PO);
159+
return false;
160+
}
147161

162+
bool isZeroingPropIvar(BinaryOperator *BOE) {
148163
if (BOE->getOpcode() == BO_Comma)
149164
return isZeroingPropIvar(BOE->getLHS()) &&
150165
isZeroingPropIvar(BOE->getRHS());
151166

152167
if (BOE->getOpcode() != BO_Assign)
153-
return false;
154-
155-
ASTContext &Ctx = Pass.Ctx;
168+
return false;
156169

157170
Expr *LHS = BOE->getLHS();
158171
if (ObjCIvarRefExpr *IV = dyn_cast<ObjCIvarRefExpr>(LHS)) {
@@ -172,25 +185,38 @@ class ZeroOutInDeallocRemover :
172185
if (!IvarBacksPropertySynthesis)
173186
return false;
174187
}
175-
else if (ObjCPropertyRefExpr *PropRefExp = dyn_cast<ObjCPropertyRefExpr>(LHS)) {
176-
// TODO: Using implicit property decl.
177-
if (PropRefExp->isImplicitProperty())
178-
return false;
179-
if (ObjCPropertyDecl *PDecl = PropRefExp->getExplicitProperty()) {
180-
if (!SynthesizedProperties.count(PDecl))
181-
return false;
182-
}
183-
}
184188
else
185189
return false;
186190

187-
Expr *RHS = BOE->getRHS();
188-
bool RHSIsNull = RHS->isNullPointerConstant(Ctx,
189-
Expr::NPC_ValueDependentIsNull);
190-
if (RHSIsNull)
191+
return isZero(BOE->getRHS());
192+
}
193+
194+
bool isZeroingPropIvar(PseudoObjectExpr *PO) {
195+
BinaryOperator *BO = dyn_cast<BinaryOperator>(PO->getSyntacticForm());
196+
if (!BO) return false;
197+
if (BO->getOpcode() != BO_Assign) return false;
198+
199+
ObjCPropertyRefExpr *PropRefExp =
200+
dyn_cast<ObjCPropertyRefExpr>(BO->getLHS()->IgnoreParens());
201+
if (!PropRefExp) return false;
202+
203+
// TODO: Using implicit property decl.
204+
if (PropRefExp->isImplicitProperty())
205+
return false;
206+
207+
if (ObjCPropertyDecl *PDecl = PropRefExp->getExplicitProperty()) {
208+
if (!SynthesizedProperties.count(PDecl))
209+
return false;
210+
}
211+
212+
return isZero(cast<OpaqueValueExpr>(BO->getRHS())->getSourceExpr());
213+
}
214+
215+
bool isZero(Expr *E) {
216+
if (E->isNullPointerConstant(Pass.Ctx, Expr::NPC_ValueDependentIsNull))
191217
return true;
192218

193-
return isZeroingPropIvar(RHS);
219+
return isZeroingPropIvar(E);
194220
}
195221
};
196222

Diff for: lib/AST/DeclBase.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,11 @@ void Decl::CheckAccessDeclContext() const {
640640
}
641641

642642
DeclContext *Decl::getNonClosureContext() {
643-
DeclContext *DC = getDeclContext();
643+
return getDeclContext()->getNonClosureAncestor();
644+
}
645+
646+
DeclContext *DeclContext::getNonClosureAncestor() {
647+
DeclContext *DC = this;
644648

645649
// This is basically "while (DC->isClosure()) DC = DC->getParent();"
646650
// except that it's significantly more efficient to cast to a known

0 commit comments

Comments
 (0)