/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- SemaPseudoObject.cpp - Semantic Analysis for Pseudo-Objects ------===// |
2 | | // |
3 | | // The LLVM Compiler Infrastructure |
4 | | // |
5 | | // This file is distributed under the University of Illinois Open Source |
6 | | // License. See LICENSE.TXT for details. |
7 | | // |
8 | | //===----------------------------------------------------------------------===// |
9 | | // |
10 | | // This file implements semantic analysis for expressions involving |
11 | | // pseudo-object references. Pseudo-objects are conceptual objects |
12 | | // whose storage is entirely abstract and all accesses to which are |
13 | | // translated through some sort of abstraction barrier. |
14 | | // |
15 | | // For example, Objective-C objects can have "properties", either |
16 | | // declared or undeclared. A property may be accessed by writing |
17 | | // expr.prop |
18 | | // where 'expr' is an r-value of Objective-C pointer type and 'prop' |
19 | | // is the name of the property. If this expression is used in a context |
20 | | // needing an r-value, it is treated as if it were a message-send |
21 | | // of the associated 'getter' selector, typically: |
22 | | // [expr prop] |
23 | | // If it is used as the LHS of a simple assignment, it is treated |
24 | | // as a message-send of the associated 'setter' selector, typically: |
25 | | // [expr setProp: RHS] |
26 | | // If it is used as the LHS of a compound assignment, or the operand |
27 | | // of a unary increment or decrement, both are required; for example, |
28 | | // 'expr.prop *= 100' would be translated to: |
29 | | // [expr setProp: [expr prop] * 100] |
30 | | // |
31 | | //===----------------------------------------------------------------------===// |
32 | | |
33 | | #include "clang/Sema/SemaInternal.h" |
34 | | #include "clang/AST/ExprCXX.h" |
35 | | #include "clang/AST/ExprObjC.h" |
36 | | #include "clang/Basic/CharInfo.h" |
37 | | #include "clang/Lex/Preprocessor.h" |
38 | | #include "clang/Sema/Initialization.h" |
39 | | #include "clang/Sema/ScopeInfo.h" |
40 | | #include "llvm/ADT/SmallString.h" |
41 | | |
42 | | using namespace clang; |
43 | | using namespace sema; |
44 | | |
45 | | namespace { |
46 | | // Basically just a very focused copy of TreeTransform. |
47 | | struct Rebuilder { |
48 | | Sema &S; |
49 | | unsigned MSPropertySubscriptCount; |
50 | | typedef llvm::function_ref<Expr *(Expr *, unsigned)> SpecificRebuilderRefTy; |
51 | | const SpecificRebuilderRefTy &SpecificCallback; |
52 | | Rebuilder(Sema &S, const SpecificRebuilderRefTy &SpecificCallback) |
53 | | : S(S), MSPropertySubscriptCount(0), |
54 | 2.43k | SpecificCallback(SpecificCallback) {} |
55 | | |
56 | 1.91k | Expr *rebuildObjCPropertyRefExpr(ObjCPropertyRefExpr *refExpr) { |
57 | 1.91k | // Fortunately, the constraint that we're rebuilding something |
58 | 1.91k | // with a base limits the number of cases here. |
59 | 1.91k | if (refExpr->isClassReceiver() || 1.91k refExpr->isSuperReceiver()1.91k ) |
60 | 1 | return refExpr; |
61 | 1.91k | |
62 | 1.91k | if (1.91k refExpr->isExplicitProperty()1.91k ) { |
63 | 1.63k | return new (S.Context) ObjCPropertyRefExpr( |
64 | 1.63k | refExpr->getExplicitProperty(), refExpr->getType(), |
65 | 1.63k | refExpr->getValueKind(), refExpr->getObjectKind(), |
66 | 1.63k | refExpr->getLocation(), SpecificCallback(refExpr->getBase(), 0)); |
67 | 1.63k | } |
68 | 281 | return new (S.Context) ObjCPropertyRefExpr( |
69 | 281 | refExpr->getImplicitPropertyGetter(), |
70 | 281 | refExpr->getImplicitPropertySetter(), refExpr->getType(), |
71 | 281 | refExpr->getValueKind(), refExpr->getObjectKind(), |
72 | 281 | refExpr->getLocation(), SpecificCallback(refExpr->getBase(), 0)); |
73 | 281 | } |
74 | 248 | Expr *rebuildObjCSubscriptRefExpr(ObjCSubscriptRefExpr *refExpr) { |
75 | 248 | assert(refExpr->getBaseExpr()); |
76 | 248 | assert(refExpr->getKeyExpr()); |
77 | 248 | |
78 | 248 | return new (S.Context) ObjCSubscriptRefExpr( |
79 | 248 | SpecificCallback(refExpr->getBaseExpr(), 0), |
80 | 248 | SpecificCallback(refExpr->getKeyExpr(), 1), refExpr->getType(), |
81 | 248 | refExpr->getValueKind(), refExpr->getObjectKind(), |
82 | 248 | refExpr->getAtIndexMethodDecl(), refExpr->setAtIndexMethodDecl(), |
83 | 248 | refExpr->getRBracket()); |
84 | 248 | } |
85 | 275 | Expr *rebuildMSPropertyRefExpr(MSPropertyRefExpr *refExpr) { |
86 | 275 | assert(refExpr->getBaseExpr()); |
87 | 275 | |
88 | 275 | return new (S.Context) MSPropertyRefExpr( |
89 | 275 | SpecificCallback(refExpr->getBaseExpr(), 0), |
90 | 275 | refExpr->getPropertyDecl(), refExpr->isArrow(), refExpr->getType(), |
91 | 275 | refExpr->getValueKind(), refExpr->getQualifierLoc(), |
92 | 275 | refExpr->getMemberLoc()); |
93 | 275 | } |
94 | 166 | Expr *rebuildMSPropertySubscriptExpr(MSPropertySubscriptExpr *refExpr) { |
95 | 166 | assert(refExpr->getBase()); |
96 | 166 | assert(refExpr->getIdx()); |
97 | 166 | |
98 | 166 | auto *NewBase = rebuild(refExpr->getBase()); |
99 | 166 | ++MSPropertySubscriptCount; |
100 | 166 | return new (S.Context) MSPropertySubscriptExpr( |
101 | 166 | NewBase, |
102 | 166 | SpecificCallback(refExpr->getIdx(), MSPropertySubscriptCount), |
103 | 166 | refExpr->getType(), refExpr->getValueKind(), refExpr->getObjectKind(), |
104 | 166 | refExpr->getRBracketLoc()); |
105 | 166 | } |
106 | | |
107 | 2.66k | Expr *rebuild(Expr *e) { |
108 | 2.66k | // Fast path: nothing to look through. |
109 | 2.66k | if (auto *PRE = dyn_cast<ObjCPropertyRefExpr>(e)) |
110 | 1.91k | return rebuildObjCPropertyRefExpr(PRE); |
111 | 755 | if (auto *755 SRE755 = dyn_cast<ObjCSubscriptRefExpr>(e)) |
112 | 248 | return rebuildObjCSubscriptRefExpr(SRE); |
113 | 507 | if (auto *507 MSPRE507 = dyn_cast<MSPropertyRefExpr>(e)) |
114 | 275 | return rebuildMSPropertyRefExpr(MSPRE); |
115 | 232 | if (auto *232 MSPSE232 = dyn_cast<MSPropertySubscriptExpr>(e)) |
116 | 166 | return rebuildMSPropertySubscriptExpr(MSPSE); |
117 | 66 | |
118 | 66 | // Otherwise, we should look through and rebuild anything that |
119 | 66 | // IgnoreParens would. |
120 | 66 | |
121 | 66 | if (ParenExpr *66 parens66 = dyn_cast<ParenExpr>(e)) { |
122 | 65 | e = rebuild(parens->getSubExpr()); |
123 | 65 | return new (S.Context) ParenExpr(parens->getLParen(), |
124 | 65 | parens->getRParen(), |
125 | 65 | e); |
126 | 65 | } |
127 | 1 | |
128 | 1 | if (UnaryOperator *1 uop1 = dyn_cast<UnaryOperator>(e)) { |
129 | 0 | assert(uop->getOpcode() == UO_Extension); |
130 | 0 | e = rebuild(uop->getSubExpr()); |
131 | 0 | return new (S.Context) UnaryOperator(e, uop->getOpcode(), |
132 | 0 | uop->getType(), |
133 | 0 | uop->getValueKind(), |
134 | 0 | uop->getObjectKind(), |
135 | 0 | uop->getOperatorLoc()); |
136 | 0 | } |
137 | 1 | |
138 | 1 | if (GenericSelectionExpr *1 gse1 = dyn_cast<GenericSelectionExpr>(e)) { |
139 | 0 | assert(!gse->isResultDependent()); |
140 | 0 | unsigned resultIndex = gse->getResultIndex(); |
141 | 0 | unsigned numAssocs = gse->getNumAssocs(); |
142 | 0 |
|
143 | 0 | SmallVector<Expr*, 8> assocs(numAssocs); |
144 | 0 | SmallVector<TypeSourceInfo*, 8> assocTypes(numAssocs); |
145 | 0 |
|
146 | 0 | for (unsigned i = 0; i != numAssocs0 ; ++i0 ) { |
147 | 0 | Expr *assoc = gse->getAssocExpr(i); |
148 | 0 | if (i == resultIndex0 ) assoc = rebuild(assoc)0 ; |
149 | 0 | assocs[i] = assoc; |
150 | 0 | assocTypes[i] = gse->getAssocTypeSourceInfo(i); |
151 | 0 | } |
152 | 0 |
|
153 | 0 | return new (S.Context) GenericSelectionExpr(S.Context, |
154 | 0 | gse->getGenericLoc(), |
155 | 0 | gse->getControllingExpr(), |
156 | 0 | assocTypes, |
157 | 0 | assocs, |
158 | 0 | gse->getDefaultLoc(), |
159 | 0 | gse->getRParenLoc(), |
160 | 0 | gse->containsUnexpandedParameterPack(), |
161 | 0 | resultIndex); |
162 | 0 | } |
163 | 1 | |
164 | 1 | if (ChooseExpr *1 ce1 = dyn_cast<ChooseExpr>(e)) { |
165 | 1 | assert(!ce->isConditionDependent()); |
166 | 1 | |
167 | 1 | Expr *LHS = ce->getLHS(), *RHS = ce->getRHS(); |
168 | 1 | Expr *&rebuiltExpr = ce->isConditionTrue() ? LHS0 : RHS1 ; |
169 | 1 | rebuiltExpr = rebuild(rebuiltExpr); |
170 | 1 | |
171 | 1 | return new (S.Context) ChooseExpr(ce->getBuiltinLoc(), |
172 | 1 | ce->getCond(), |
173 | 1 | LHS, RHS, |
174 | 1 | rebuiltExpr->getType(), |
175 | 1 | rebuiltExpr->getValueKind(), |
176 | 1 | rebuiltExpr->getObjectKind(), |
177 | 1 | ce->getRParenLoc(), |
178 | 1 | ce->isConditionTrue(), |
179 | 1 | rebuiltExpr->isTypeDependent(), |
180 | 1 | rebuiltExpr->isValueDependent()); |
181 | 1 | } |
182 | 0 |
|
183 | 0 | llvm_unreachable0 ("bad expression to rebuild!"); |
184 | 0 | } |
185 | | }; |
186 | | |
187 | | class PseudoOpBuilder { |
188 | | public: |
189 | | Sema &S; |
190 | | unsigned ResultIndex; |
191 | | SourceLocation GenericLoc; |
192 | | SmallVector<Expr *, 4> Semantics; |
193 | | |
194 | | PseudoOpBuilder(Sema &S, SourceLocation genericLoc) |
195 | | : S(S), ResultIndex(PseudoObjectExpr::NoResult), |
196 | 2.67k | GenericLoc(genericLoc) {} |
197 | | |
198 | 2.67k | virtual ~PseudoOpBuilder() {} |
199 | | |
200 | | /// Add a normal semantic expression. |
201 | 5.10k | void addSemanticExpr(Expr *semantic) { |
202 | 5.10k | Semantics.push_back(semantic); |
203 | 5.10k | } |
204 | | |
205 | | /// Add the 'result' semantic expression. |
206 | 1.64k | void addResultSemanticExpr(Expr *resultExpr) { |
207 | 1.64k | assert(ResultIndex == PseudoObjectExpr::NoResult); |
208 | 1.64k | ResultIndex = Semantics.size(); |
209 | 1.64k | Semantics.push_back(resultExpr); |
210 | 1.64k | } |
211 | | |
212 | | ExprResult buildRValueOperation(Expr *op); |
213 | | ExprResult buildAssignmentOperation(Scope *Sc, |
214 | | SourceLocation opLoc, |
215 | | BinaryOperatorKind opcode, |
216 | | Expr *LHS, Expr *RHS); |
217 | | ExprResult buildIncDecOperation(Scope *Sc, SourceLocation opLoc, |
218 | | UnaryOperatorKind opcode, |
219 | | Expr *op); |
220 | | |
221 | | virtual ExprResult complete(Expr *syntacticForm); |
222 | | |
223 | | OpaqueValueExpr *capture(Expr *op); |
224 | | OpaqueValueExpr *captureValueAsResult(Expr *op); |
225 | | |
226 | 512 | void setResultToLastSemantic() { |
227 | 512 | assert(ResultIndex == PseudoObjectExpr::NoResult); |
228 | 512 | ResultIndex = Semantics.size() - 1; |
229 | 512 | } |
230 | | |
231 | | /// Return true if assignments have a non-void result. |
232 | 872 | static bool CanCaptureValue(Expr *exp) { |
233 | 872 | if (exp->isGLValue()) |
234 | 7 | return true; |
235 | 865 | QualType ty = exp->getType(); |
236 | 865 | assert(!ty->isIncompleteType()); |
237 | 865 | assert(!ty->isDependentType()); |
238 | 865 | |
239 | 865 | if (const CXXRecordDecl *ClassDecl = ty->getAsCXXRecordDecl()) |
240 | 18 | return ClassDecl->isTriviallyCopyable(); |
241 | 847 | return true; |
242 | 847 | } |
243 | | |
244 | | virtual Expr *rebuildAndCaptureObject(Expr *) = 0; |
245 | | virtual ExprResult buildGet() = 0; |
246 | | virtual ExprResult buildSet(Expr *, SourceLocation, |
247 | | bool captureSetValueAsResult) = 0; |
248 | | /// \brief Should the result of an assignment be the formal result of the |
249 | | /// setter call or the value that was passed to the setter? |
250 | | /// |
251 | | /// Different pseudo-object language features use different language rules |
252 | | /// for this. |
253 | | /// The default is to use the set value. Currently, this affects the |
254 | | /// behavior of simple assignments, compound assignments, and prefix |
255 | | /// increment and decrement. |
256 | | /// Postfix increment and decrement always use the getter result as the |
257 | | /// expression result. |
258 | | /// |
259 | | /// If this method returns true, and the set value isn't capturable for |
260 | | /// some reason, the result of the expression will be void. |
261 | 1.69k | virtual bool captureSetValueAsResult() const { return true; } |
262 | | }; |
263 | | |
264 | | /// A PseudoOpBuilder for Objective-C \@properties. |
265 | | class ObjCPropertyOpBuilder : public PseudoOpBuilder { |
266 | | ObjCPropertyRefExpr *RefExpr; |
267 | | ObjCPropertyRefExpr *SyntacticRefExpr; |
268 | | OpaqueValueExpr *InstanceReceiver; |
269 | | ObjCMethodDecl *Getter; |
270 | | |
271 | | ObjCMethodDecl *Setter; |
272 | | Selector SetterSelector; |
273 | | Selector GetterSelector; |
274 | | |
275 | | public: |
276 | | ObjCPropertyOpBuilder(Sema &S, ObjCPropertyRefExpr *refExpr) : |
277 | | PseudoOpBuilder(S, refExpr->getLocation()), RefExpr(refExpr), |
278 | | SyntacticRefExpr(nullptr), InstanceReceiver(nullptr), Getter(nullptr), |
279 | 2.16k | Setter(nullptr) { |
280 | 2.16k | } |
281 | | |
282 | | ExprResult buildRValueOperation(Expr *op); |
283 | | ExprResult buildAssignmentOperation(Scope *Sc, |
284 | | SourceLocation opLoc, |
285 | | BinaryOperatorKind opcode, |
286 | | Expr *LHS, Expr *RHS); |
287 | | ExprResult buildIncDecOperation(Scope *Sc, SourceLocation opLoc, |
288 | | UnaryOperatorKind opcode, |
289 | | Expr *op); |
290 | | |
291 | | bool tryBuildGetOfReference(Expr *op, ExprResult &result); |
292 | | bool findSetter(bool warn=true); |
293 | | bool findGetter(); |
294 | | void DiagnoseUnsupportedPropertyUse(); |
295 | | |
296 | | Expr *rebuildAndCaptureObject(Expr *syntacticBase) override; |
297 | | ExprResult buildGet() override; |
298 | | ExprResult buildSet(Expr *op, SourceLocation, bool) override; |
299 | | ExprResult complete(Expr *SyntacticForm) override; |
300 | | |
301 | | bool isWeakProperty() const; |
302 | | }; |
303 | | |
304 | | /// A PseudoOpBuilder for Objective-C array/dictionary indexing. |
305 | | class ObjCSubscriptOpBuilder : public PseudoOpBuilder { |
306 | | ObjCSubscriptRefExpr *RefExpr; |
307 | | OpaqueValueExpr *InstanceBase; |
308 | | OpaqueValueExpr *InstanceKey; |
309 | | ObjCMethodDecl *AtIndexGetter; |
310 | | Selector AtIndexGetterSelector; |
311 | | |
312 | | ObjCMethodDecl *AtIndexSetter; |
313 | | Selector AtIndexSetterSelector; |
314 | | |
315 | | public: |
316 | | ObjCSubscriptOpBuilder(Sema &S, ObjCSubscriptRefExpr *refExpr) : |
317 | | PseudoOpBuilder(S, refExpr->getSourceRange().getBegin()), |
318 | | RefExpr(refExpr), |
319 | | InstanceBase(nullptr), InstanceKey(nullptr), |
320 | 258 | AtIndexGetter(nullptr), AtIndexSetter(nullptr) {} |
321 | | |
322 | | ExprResult buildRValueOperation(Expr *op); |
323 | | ExprResult buildAssignmentOperation(Scope *Sc, |
324 | | SourceLocation opLoc, |
325 | | BinaryOperatorKind opcode, |
326 | | Expr *LHS, Expr *RHS); |
327 | | Expr *rebuildAndCaptureObject(Expr *syntacticBase) override; |
328 | | |
329 | | bool findAtIndexGetter(); |
330 | | bool findAtIndexSetter(); |
331 | | |
332 | | ExprResult buildGet() override; |
333 | | ExprResult buildSet(Expr *op, SourceLocation, bool) override; |
334 | | }; |
335 | | |
336 | | class MSPropertyOpBuilder : public PseudoOpBuilder { |
337 | | MSPropertyRefExpr *RefExpr; |
338 | | OpaqueValueExpr *InstanceBase; |
339 | | SmallVector<Expr *, 4> CallArgs; |
340 | | |
341 | | MSPropertyRefExpr *getBaseMSProperty(MSPropertySubscriptExpr *E); |
342 | | |
343 | | public: |
344 | | MSPropertyOpBuilder(Sema &S, MSPropertyRefExpr *refExpr) : |
345 | | PseudoOpBuilder(S, refExpr->getSourceRange().getBegin()), |
346 | 175 | RefExpr(refExpr), InstanceBase(nullptr) {} |
347 | | MSPropertyOpBuilder(Sema &S, MSPropertySubscriptExpr *refExpr) |
348 | | : PseudoOpBuilder(S, refExpr->getSourceRange().getBegin()), |
349 | 72 | InstanceBase(nullptr) { |
350 | 72 | RefExpr = getBaseMSProperty(refExpr); |
351 | 72 | } |
352 | | |
353 | | Expr *rebuildAndCaptureObject(Expr *) override; |
354 | | ExprResult buildGet() override; |
355 | | ExprResult buildSet(Expr *op, SourceLocation, bool) override; |
356 | 156 | bool captureSetValueAsResult() const override { return false; } |
357 | | }; |
358 | | } |
359 | | |
360 | | /// Capture the given expression in an OpaqueValueExpr. |
361 | 4.18k | OpaqueValueExpr *PseudoOpBuilder::capture(Expr *e) { |
362 | 4.18k | // Make a new OVE whose source is the given expression. |
363 | 4.18k | OpaqueValueExpr *captured = |
364 | 4.18k | new (S.Context) OpaqueValueExpr(GenericLoc, e->getType(), |
365 | 4.18k | e->getValueKind(), e->getObjectKind(), |
366 | 4.18k | e); |
367 | 4.18k | |
368 | 4.18k | // Make sure we bind that in the semantics. |
369 | 4.18k | addSemanticExpr(captured); |
370 | 4.18k | return captured; |
371 | 4.18k | } |
372 | | |
373 | | /// Capture the given expression as the result of this pseudo-object |
374 | | /// operation. This routine is safe against expressions which may |
375 | | /// already be captured. |
376 | | /// |
377 | | /// \returns the captured expression, which will be the |
378 | | /// same as the input if the input was already captured |
379 | 830 | OpaqueValueExpr *PseudoOpBuilder::captureValueAsResult(Expr *e) { |
380 | 830 | assert(ResultIndex == PseudoObjectExpr::NoResult); |
381 | 830 | |
382 | 830 | // If the expression hasn't already been captured, just capture it |
383 | 830 | // and set the new semantic |
384 | 830 | if (!isa<OpaqueValueExpr>(e)830 ) { |
385 | 469 | OpaqueValueExpr *cap = capture(e); |
386 | 469 | setResultToLastSemantic(); |
387 | 469 | return cap; |
388 | 469 | } |
389 | 361 | |
390 | 361 | // Otherwise, it must already be one of our semantic expressions; |
391 | 361 | // set ResultIndex to its index. |
392 | 361 | unsigned index = 0; |
393 | 361 | for (;; ++index343 ) { |
394 | 704 | assert(index < Semantics.size() && |
395 | 704 | "captured expression not found in semantics!"); |
396 | 704 | if (e == Semantics[index]704 ) break361 ; |
397 | 704 | } |
398 | 830 | ResultIndex = index; |
399 | 830 | return cast<OpaqueValueExpr>(e); |
400 | 830 | } |
401 | | |
402 | | /// The routine which creates the final PseudoObjectExpr. |
403 | 2.56k | ExprResult PseudoOpBuilder::complete(Expr *syntactic) { |
404 | 2.56k | return PseudoObjectExpr::Create(S.Context, syntactic, |
405 | 2.56k | Semantics, ResultIndex); |
406 | 2.56k | } |
407 | | |
408 | | /// The main skeleton for building an r-value operation. |
409 | 1.67k | ExprResult PseudoOpBuilder::buildRValueOperation(Expr *op) { |
410 | 1.67k | Expr *syntacticBase = rebuildAndCaptureObject(op); |
411 | 1.67k | |
412 | 1.67k | ExprResult getExpr = buildGet(); |
413 | 1.67k | if (getExpr.isInvalid()1.67k ) return ExprError()32 ; |
414 | 1.64k | addResultSemanticExpr(getExpr.get()); |
415 | 1.64k | |
416 | 1.64k | return complete(syntacticBase); |
417 | 1.64k | } |
418 | | |
419 | | /// The basic skeleton for building a simple or compound |
420 | | /// assignment operation. |
421 | | ExprResult |
422 | | PseudoOpBuilder::buildAssignmentOperation(Scope *Sc, SourceLocation opcLoc, |
423 | | BinaryOperatorKind opcode, |
424 | 921 | Expr *LHS, Expr *RHS) { |
425 | 921 | assert(BinaryOperator::isAssignmentOp(opcode)); |
426 | 921 | |
427 | 921 | Expr *syntacticLHS = rebuildAndCaptureObject(LHS); |
428 | 921 | OpaqueValueExpr *capturedRHS = capture(RHS); |
429 | 921 | |
430 | 921 | // In some very specific cases, semantic analysis of the RHS as an |
431 | 921 | // expression may require it to be rewritten. In these cases, we |
432 | 921 | // cannot safely keep the OVE around. Fortunately, we don't really |
433 | 921 | // need to: we don't use this particular OVE in multiple places, and |
434 | 921 | // no clients rely that closely on matching up expressions in the |
435 | 921 | // semantic expression with expressions from the syntactic form. |
436 | 921 | Expr *semanticRHS = capturedRHS; |
437 | 921 | if (RHS->hasPlaceholderType() || 921 isa<InitListExpr>(RHS)918 ) { |
438 | 7 | semanticRHS = RHS; |
439 | 7 | Semantics.pop_back(); |
440 | 7 | } |
441 | 921 | |
442 | 921 | Expr *syntactic; |
443 | 921 | |
444 | 921 | ExprResult result; |
445 | 921 | if (opcode == BO_Assign921 ) { |
446 | 884 | result = semanticRHS; |
447 | 884 | syntactic = new (S.Context) BinaryOperator(syntacticLHS, capturedRHS, |
448 | 884 | opcode, capturedRHS->getType(), |
449 | 884 | capturedRHS->getValueKind(), |
450 | 884 | OK_Ordinary, opcLoc, |
451 | 884 | FPOptions()); |
452 | 921 | } else { |
453 | 37 | ExprResult opLHS = buildGet(); |
454 | 37 | if (opLHS.isInvalid()37 ) return ExprError()0 ; |
455 | 37 | |
456 | 37 | // Build an ordinary, non-compound operation. |
457 | 37 | BinaryOperatorKind nonCompound = |
458 | 37 | BinaryOperator::getOpForCompoundAssignment(opcode); |
459 | 37 | result = S.BuildBinOp(Sc, opcLoc, nonCompound, opLHS.get(), semanticRHS); |
460 | 37 | if (result.isInvalid()37 ) return ExprError()0 ; |
461 | 37 | |
462 | 37 | syntactic = |
463 | 37 | new (S.Context) CompoundAssignOperator(syntacticLHS, capturedRHS, opcode, |
464 | 37 | result.get()->getType(), |
465 | 37 | result.get()->getValueKind(), |
466 | 37 | OK_Ordinary, |
467 | 37 | opLHS.get()->getType(), |
468 | 37 | result.get()->getType(), |
469 | 37 | opcLoc, FPOptions()); |
470 | 37 | } |
471 | 921 | |
472 | 921 | // The result of the assignment, if not void, is the value set into |
473 | 921 | // the l-value. |
474 | 921 | result = buildSet(result.get(), opcLoc, captureSetValueAsResult()); |
475 | 921 | if (result.isInvalid()921 ) return ExprError()41 ; |
476 | 880 | addSemanticExpr(result.get()); |
477 | 880 | if (!captureSetValueAsResult() && 880 !result.get()->getType()->isVoidType()60 && |
478 | 26 | (result.get()->isTypeDependent() || 26 CanCaptureValue(result.get())17 )) |
479 | 26 | setResultToLastSemantic(); |
480 | 921 | |
481 | 921 | return complete(syntactic); |
482 | 921 | } |
483 | | |
484 | | /// The basic skeleton for building an increment or decrement |
485 | | /// operation. |
486 | | ExprResult |
487 | | PseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc, |
488 | | UnaryOperatorKind opcode, |
489 | 41 | Expr *op) { |
490 | 41 | assert(UnaryOperator::isIncrementDecrementOp(opcode)); |
491 | 41 | |
492 | 41 | Expr *syntacticOp = rebuildAndCaptureObject(op); |
493 | 41 | |
494 | 41 | // Load the value. |
495 | 41 | ExprResult result = buildGet(); |
496 | 41 | if (result.isInvalid()41 ) return ExprError()1 ; |
497 | 40 | |
498 | 40 | QualType resultType = result.get()->getType(); |
499 | 40 | |
500 | 40 | // That's the postfix result. |
501 | 40 | if (UnaryOperator::isPostfix(opcode) && |
502 | 40 | (result.get()->isTypeDependent() || 14 CanCaptureValue(result.get())11 )) { |
503 | 11 | result = capture(result.get()); |
504 | 11 | setResultToLastSemantic(); |
505 | 11 | } |
506 | 40 | |
507 | 40 | // Add or subtract a literal 1. |
508 | 40 | llvm::APInt oneV(S.Context.getTypeSize(S.Context.IntTy), 1); |
509 | 40 | Expr *one = IntegerLiteral::Create(S.Context, oneV, S.Context.IntTy, |
510 | 40 | GenericLoc); |
511 | 40 | |
512 | 40 | if (UnaryOperator::isIncrementOp(opcode)40 ) { |
513 | 38 | result = S.BuildBinOp(Sc, opcLoc, BO_Add, result.get(), one); |
514 | 40 | } else { |
515 | 2 | result = S.BuildBinOp(Sc, opcLoc, BO_Sub, result.get(), one); |
516 | 2 | } |
517 | 40 | if (result.isInvalid()40 ) return ExprError()0 ; |
518 | 40 | |
519 | 40 | // Store that back into the result. The value stored is the result |
520 | 40 | // of a prefix operation. |
521 | 40 | result = buildSet(result.get(), opcLoc, UnaryOperator::isPrefix(opcode) && |
522 | 26 | captureSetValueAsResult()); |
523 | 40 | if (result.isInvalid()40 ) return ExprError()0 ; |
524 | 40 | addSemanticExpr(result.get()); |
525 | 40 | if (UnaryOperator::isPrefix(opcode) && 40 !captureSetValueAsResult()26 && |
526 | 7 | !result.get()->getType()->isVoidType() && |
527 | 6 | (result.get()->isTypeDependent() || 6 CanCaptureValue(result.get())5 )) |
528 | 6 | setResultToLastSemantic(); |
529 | 41 | |
530 | 41 | UnaryOperator *syntactic = |
531 | 41 | new (S.Context) UnaryOperator(syntacticOp, opcode, resultType, |
532 | 41 | VK_LValue, OK_Ordinary, opcLoc); |
533 | 41 | return complete(syntactic); |
534 | 41 | } |
535 | | |
536 | | |
537 | | //===----------------------------------------------------------------------===// |
538 | | // Objective-C @property and implicit property references |
539 | | //===----------------------------------------------------------------------===// |
540 | | |
541 | | /// Look up a method in the receiver type of an Objective-C property |
542 | | /// reference. |
543 | | static ObjCMethodDecl *LookupMethodInReceiverType(Sema &S, Selector sel, |
544 | 2.36k | const ObjCPropertyRefExpr *PRE) { |
545 | 2.36k | if (PRE->isObjectReceiver()2.36k ) { |
546 | 2.29k | const ObjCObjectPointerType *PT = |
547 | 2.29k | PRE->getBase()->getType()->castAs<ObjCObjectPointerType>(); |
548 | 2.29k | |
549 | 2.29k | // Special case for 'self' in class method implementations. |
550 | 2.29k | if (PT->isObjCClassType() && |
551 | 2.29k | S.isSelfExpr(const_cast<Expr*>(PRE->getBase()))0 ) { |
552 | 0 | // This cast is safe because isSelfExpr is only true within |
553 | 0 | // methods. |
554 | 0 | ObjCMethodDecl *method = |
555 | 0 | cast<ObjCMethodDecl>(S.CurContext->getNonClosureAncestor()); |
556 | 0 | return S.LookupMethodInObjectType(sel, |
557 | 0 | S.Context.getObjCInterfaceType(method->getClassInterface()), |
558 | 0 | /*instance*/ false); |
559 | 0 | } |
560 | 2.29k | |
561 | 2.29k | return S.LookupMethodInObjectType(sel, PT->getPointeeType(), true); |
562 | 2.29k | } |
563 | 69 | |
564 | 69 | if (69 PRE->isSuperReceiver()69 ) { |
565 | 69 | if (const ObjCObjectPointerType *PT = |
566 | 69 | PRE->getSuperReceiverType()->getAs<ObjCObjectPointerType>()) |
567 | 69 | return S.LookupMethodInObjectType(sel, PT->getPointeeType(), true); |
568 | 0 |
|
569 | 0 | return S.LookupMethodInObjectType(sel, PRE->getSuperReceiverType(), false); |
570 | 0 | } |
571 | 0 |
|
572 | 69 | assert(PRE->isClassReceiver() && "Invalid expression"); |
573 | 0 | QualType IT = S.Context.getObjCInterfaceType(PRE->getClassReceiver()); |
574 | 0 | return S.LookupMethodInObjectType(sel, IT, false); |
575 | 0 | } |
576 | | |
577 | 2.13k | bool ObjCPropertyOpBuilder::isWeakProperty() const { |
578 | 2.13k | QualType T; |
579 | 2.13k | if (RefExpr->isExplicitProperty()2.13k ) { |
580 | 1.67k | const ObjCPropertyDecl *Prop = RefExpr->getExplicitProperty(); |
581 | 1.67k | if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak) |
582 | 198 | return true; |
583 | 1.47k | |
584 | 1.47k | T = Prop->getType(); |
585 | 2.13k | } else if (459 Getter459 ) { |
586 | 362 | T = Getter->getReturnType(); |
587 | 459 | } else { |
588 | 97 | return false; |
589 | 97 | } |
590 | 1.83k | |
591 | 1.83k | return T.getObjCLifetime() == Qualifiers::OCL_Weak; |
592 | 1.83k | } |
593 | | |
594 | 1.48k | bool ObjCPropertyOpBuilder::findGetter() { |
595 | 1.48k | if (Getter1.48k ) return true54 ; |
596 | 1.43k | |
597 | 1.43k | // For implicit properties, just trust the lookup we already did. |
598 | 1.43k | if (1.43k RefExpr->isImplicitProperty()1.43k ) { |
599 | 365 | if ((Getter = RefExpr->getImplicitPropertyGetter())365 ) { |
600 | 363 | GetterSelector = Getter->getSelector(); |
601 | 363 | return true; |
602 | 363 | } |
603 | 2 | else { |
604 | 2 | // Must build the getter selector the hard way. |
605 | 2 | ObjCMethodDecl *setter = RefExpr->getImplicitPropertySetter(); |
606 | 2 | assert(setter && "both setter and getter are null - cannot happen"); |
607 | 2 | IdentifierInfo *setterName = |
608 | 2 | setter->getSelector().getIdentifierInfoForSlot(0); |
609 | 2 | IdentifierInfo *getterName = |
610 | 2 | &S.Context.Idents.get(setterName->getName().substr(3)); |
611 | 2 | GetterSelector = |
612 | 2 | S.PP.getSelectorTable().getNullarySelector(getterName); |
613 | 2 | return false; |
614 | 2 | } |
615 | 1.06k | } |
616 | 1.06k | |
617 | 1.06k | ObjCPropertyDecl *prop = RefExpr->getExplicitProperty(); |
618 | 1.06k | Getter = LookupMethodInReceiverType(S, prop->getGetterName(), RefExpr); |
619 | 1.06k | return (Getter != nullptr); |
620 | 1.06k | } |
621 | | |
622 | | /// Try to find the most accurate setter declaration for the property |
623 | | /// reference. |
624 | | /// |
625 | | /// \return true if a setter was found, in which case Setter |
626 | 1.54k | bool ObjCPropertyOpBuilder::findSetter(bool warn) { |
627 | 1.54k | // For implicit properties, just trust the lookup we already did. |
628 | 1.54k | if (RefExpr->isImplicitProperty()1.54k ) { |
629 | 247 | if (ObjCMethodDecl *setter247 = RefExpr->getImplicitPropertySetter()) { |
630 | 240 | Setter = setter; |
631 | 240 | SetterSelector = setter->getSelector(); |
632 | 240 | return true; |
633 | 0 | } else { |
634 | 7 | IdentifierInfo *getterName = |
635 | 7 | RefExpr->getImplicitPropertyGetter()->getSelector() |
636 | 7 | .getIdentifierInfoForSlot(0); |
637 | 7 | SetterSelector = |
638 | 7 | SelectorTable::constructSetterSelector(S.PP.getIdentifierTable(), |
639 | 7 | S.PP.getSelectorTable(), |
640 | 7 | getterName); |
641 | 7 | return false; |
642 | 7 | } |
643 | 1.29k | } |
644 | 1.29k | |
645 | 1.29k | // For explicit properties, this is more involved. |
646 | 1.29k | ObjCPropertyDecl *prop = RefExpr->getExplicitProperty(); |
647 | 1.29k | SetterSelector = prop->getSetterName(); |
648 | 1.29k | |
649 | 1.29k | // Do a normal method lookup first. |
650 | 1.29k | if (ObjCMethodDecl *setter = |
651 | 1.29k | LookupMethodInReceiverType(S, SetterSelector, RefExpr)) { |
652 | 1.29k | if (setter->isPropertyAccessor() && 1.29k warn1.26k ) |
653 | 633 | if (const ObjCInterfaceDecl *633 IFace633 = |
654 | 586 | dyn_cast<ObjCInterfaceDecl>(setter->getDeclContext())) { |
655 | 586 | StringRef thisPropertyName = prop->getName(); |
656 | 586 | // Try flipping the case of the first character. |
657 | 586 | char front = thisPropertyName.front(); |
658 | 586 | front = isLowercase(front) ? toUppercase(front)559 : toLowercase(front)27 ; |
659 | 586 | SmallString<100> PropertyName = thisPropertyName; |
660 | 586 | PropertyName[0] = front; |
661 | 586 | IdentifierInfo *AltMember = &S.PP.getIdentifierTable().get(PropertyName); |
662 | 586 | if (ObjCPropertyDecl *prop1 = IFace->FindPropertyDeclaration( |
663 | 586 | AltMember, prop->getQueryKind())) |
664 | 4 | if (4 prop != prop1 && 4 (prop1->getSetterMethodDecl() == setter)4 ) { |
665 | 4 | S.Diag(RefExpr->getExprLoc(), diag::err_property_setter_ambiguous_use) |
666 | 4 | << prop << prop1 << setter->getSelector(); |
667 | 4 | S.Diag(prop->getLocation(), diag::note_property_declare); |
668 | 4 | S.Diag(prop1->getLocation(), diag::note_property_declare); |
669 | 4 | } |
670 | 633 | } |
671 | 1.29k | Setter = setter; |
672 | 1.29k | return true; |
673 | 1.29k | } |
674 | 6 | |
675 | 6 | // That can fail in the somewhat crazy situation that we're |
676 | 6 | // type-checking a message send within the @interface declaration |
677 | 6 | // that declared the @property. But it's not clear that that's |
678 | 6 | // valuable to support. |
679 | 6 | |
680 | 6 | return false; |
681 | 6 | } |
682 | | |
683 | 1 | void ObjCPropertyOpBuilder::DiagnoseUnsupportedPropertyUse() { |
684 | 1 | if (S.getCurLexicalContext()->isObjCContainer() && |
685 | 1 | S.getCurLexicalContext()->getDeclKind() != Decl::ObjCCategoryImpl && |
686 | 1 | S.getCurLexicalContext()->getDeclKind() != Decl::ObjCImplementation1 ) { |
687 | 1 | if (ObjCPropertyDecl *prop1 = RefExpr->getExplicitProperty()) { |
688 | 1 | S.Diag(RefExpr->getLocation(), |
689 | 1 | diag::err_property_function_in_objc_container); |
690 | 1 | S.Diag(prop->getLocation(), diag::note_property_declare); |
691 | 1 | } |
692 | 1 | } |
693 | 1 | } |
694 | | |
695 | | /// Capture the base object of an Objective-C property expression. |
696 | 2.14k | Expr *ObjCPropertyOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) { |
697 | 2.14k | assert(InstanceReceiver == nullptr); |
698 | 2.14k | |
699 | 2.14k | // If we have a base, capture it in an OVE and rebuild the syntactic |
700 | 2.14k | // form to use the OVE as its base. |
701 | 2.14k | if (RefExpr->isObjectReceiver()2.14k ) { |
702 | 1.90k | InstanceReceiver = capture(RefExpr->getBase()); |
703 | 1.90k | syntacticBase = Rebuilder(S, [=](Expr *, unsigned) -> Expr * { |
704 | 1.90k | return InstanceReceiver; |
705 | 1.90k | }).rebuild(syntacticBase); |
706 | 1.90k | } |
707 | 2.14k | |
708 | 2.14k | if (ObjCPropertyRefExpr * |
709 | 2.14k | refE = dyn_cast<ObjCPropertyRefExpr>(syntacticBase->IgnoreParens())) |
710 | 2.14k | SyntacticRefExpr = refE; |
711 | 2.14k | |
712 | 2.14k | return syntacticBase; |
713 | 2.14k | } |
714 | | |
715 | | /// Load from an Objective-C property reference. |
716 | 1.42k | ExprResult ObjCPropertyOpBuilder::buildGet() { |
717 | 1.42k | findGetter(); |
718 | 1.42k | if (!Getter1.42k ) { |
719 | 1 | DiagnoseUnsupportedPropertyUse(); |
720 | 1 | return ExprError(); |
721 | 1 | } |
722 | 1.42k | |
723 | 1.42k | if (1.42k SyntacticRefExpr1.42k ) |
724 | 1.42k | SyntacticRefExpr->setIsMessagingGetter(); |
725 | 1.42k | |
726 | 1.42k | QualType receiverType = RefExpr->getReceiverType(S.Context); |
727 | 1.42k | if (!Getter->isImplicit()) |
728 | 329 | S.DiagnoseUseOfDecl(Getter, GenericLoc, nullptr, true); |
729 | 1.42k | // Build a message-send. |
730 | 1.42k | ExprResult msg; |
731 | 1.42k | if ((Getter->isInstanceMethod() && 1.42k !RefExpr->isClassReceiver()1.27k ) || |
732 | 1.42k | RefExpr->isObjectReceiver()153 ) { |
733 | 1.27k | assert(InstanceReceiver || RefExpr->isSuperReceiver()); |
734 | 1.27k | msg = S.BuildInstanceMessageImplicit(InstanceReceiver, receiverType, |
735 | 1.27k | GenericLoc, Getter->getSelector(), |
736 | 1.27k | Getter, None); |
737 | 1.42k | } else { |
738 | 150 | msg = S.BuildClassMessageImplicit(receiverType, RefExpr->isSuperReceiver(), |
739 | 150 | GenericLoc, Getter->getSelector(), |
740 | 150 | Getter, None); |
741 | 150 | } |
742 | 1.42k | return msg; |
743 | 1.42k | } |
744 | | |
745 | | /// Store to an Objective-C property reference. |
746 | | /// |
747 | | /// \param captureSetValueAsResult If true, capture the actual |
748 | | /// value being set as the value of the property operation. |
749 | | ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc, |
750 | 764 | bool captureSetValueAsResult) { |
751 | 764 | if (!findSetter(false)764 ) { |
752 | 0 | DiagnoseUnsupportedPropertyUse(); |
753 | 0 | return ExprError(); |
754 | 0 | } |
755 | 764 | |
756 | 764 | if (764 SyntacticRefExpr764 ) |
757 | 764 | SyntacticRefExpr->setIsMessagingSetter(); |
758 | 764 | |
759 | 764 | QualType receiverType = RefExpr->getReceiverType(S.Context); |
760 | 764 | |
761 | 764 | // Use assignment constraints when possible; they give us better |
762 | 764 | // diagnostics. "When possible" basically means anything except a |
763 | 764 | // C++ class type. |
764 | 764 | if (!S.getLangOpts().CPlusPlus || 764 !op->getType()->isRecordType()128 ) { |
765 | 745 | QualType paramType = (*Setter->param_begin())->getType() |
766 | 745 | .substObjCMemberType( |
767 | 745 | receiverType, |
768 | 745 | Setter->getDeclContext(), |
769 | 745 | ObjCSubstitutionContext::Parameter); |
770 | 745 | if (!S.getLangOpts().CPlusPlus || 745 !paramType->isRecordType()109 ) { |
771 | 742 | ExprResult opResult = op; |
772 | 742 | Sema::AssignConvertType assignResult |
773 | 742 | = S.CheckSingleAssignmentConstraints(paramType, opResult); |
774 | 742 | if (opResult.isInvalid() || |
775 | 730 | S.DiagnoseAssignmentResult(assignResult, opcLoc, paramType, |
776 | 730 | op->getType(), opResult.get(), |
777 | 730 | Sema::AA_Assigning)) |
778 | 12 | return ExprError(); |
779 | 730 | |
780 | 730 | op = opResult.get(); |
781 | 730 | assert(op && "successful assignment left argument invalid?"); |
782 | 730 | } |
783 | 745 | } |
784 | 764 | |
785 | 764 | // Arguments. |
786 | 752 | Expr *args[] = { op }; |
787 | 752 | |
788 | 752 | // Build a message-send. |
789 | 752 | ExprResult msg; |
790 | 752 | if (!Setter->isImplicit()) |
791 | 118 | S.DiagnoseUseOfDecl(Setter, GenericLoc, nullptr, true); |
792 | 752 | if ((Setter->isInstanceMethod() && 752 !RefExpr->isClassReceiver()728 ) || |
793 | 752 | RefExpr->isObjectReceiver()28 ) { |
794 | 725 | msg = S.BuildInstanceMessageImplicit(InstanceReceiver, receiverType, |
795 | 725 | GenericLoc, SetterSelector, Setter, |
796 | 725 | MultiExprArg(args, 1)); |
797 | 752 | } else { |
798 | 27 | msg = S.BuildClassMessageImplicit(receiverType, RefExpr->isSuperReceiver(), |
799 | 27 | GenericLoc, |
800 | 27 | SetterSelector, Setter, |
801 | 27 | MultiExprArg(args, 1)); |
802 | 27 | } |
803 | 752 | |
804 | 752 | if (!msg.isInvalid() && 752 captureSetValueAsResult752 ) { |
805 | 748 | ObjCMessageExpr *msgExpr = |
806 | 748 | cast<ObjCMessageExpr>(msg.get()->IgnoreImplicit()); |
807 | 748 | Expr *arg = msgExpr->getArg(0); |
808 | 748 | if (CanCaptureValue(arg)) |
809 | 739 | msgExpr->setArg(0, captureValueAsResult(arg)); |
810 | 748 | } |
811 | 752 | |
812 | 752 | return msg; |
813 | 764 | } |
814 | | |
815 | | /// @property-specific behavior for doing lvalue-to-rvalue conversion. |
816 | 1.39k | ExprResult ObjCPropertyOpBuilder::buildRValueOperation(Expr *op) { |
817 | 1.39k | // Explicit properties always have getters, but implicit ones don't. |
818 | 1.39k | // Check that before proceeding. |
819 | 1.39k | if (RefExpr->isImplicitProperty() && 1.39k !RefExpr->getImplicitPropertyGetter()354 ) { |
820 | 12 | S.Diag(RefExpr->getLocation(), diag::err_getter_not_found) |
821 | 12 | << RefExpr->getSourceRange(); |
822 | 12 | return ExprError(); |
823 | 12 | } |
824 | 1.37k | |
825 | 1.37k | ExprResult result = PseudoOpBuilder::buildRValueOperation(op); |
826 | 1.37k | if (result.isInvalid()1.37k ) return ExprError()1 ; |
827 | 1.37k | |
828 | 1.37k | if (1.37k RefExpr->isExplicitProperty() && 1.37k !Getter->hasRelatedResultType()1.03k ) |
829 | 1.02k | S.DiagnosePropertyAccessorMismatch(RefExpr->getExplicitProperty(), |
830 | 1.02k | Getter, RefExpr->getLocation()); |
831 | 1.37k | |
832 | 1.37k | // As a special case, if the method returns 'id', try to get |
833 | 1.37k | // a better type from the property. |
834 | 1.37k | if (RefExpr->isExplicitProperty() && 1.37k result.get()->isRValue()1.03k ) { |
835 | 1.01k | QualType receiverType = RefExpr->getReceiverType(S.Context); |
836 | 1.01k | QualType propType = RefExpr->getExplicitProperty() |
837 | 1.01k | ->getUsageType(receiverType); |
838 | 1.01k | if (result.get()->getType()->isObjCIdType()1.01k ) { |
839 | 154 | if (const ObjCObjectPointerType *ptr |
840 | 154 | = propType->getAs<ObjCObjectPointerType>()) { |
841 | 154 | if (!ptr->isObjCIdType()) |
842 | 4 | result = S.ImpCastExprToType(result.get(), propType, CK_BitCast); |
843 | 154 | } |
844 | 154 | } |
845 | 1.01k | if (propType.getObjCLifetime() == Qualifiers::OCL_Weak && |
846 | 4 | !S.Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, |
847 | 4 | RefExpr->getLocation())) |
848 | 4 | S.getCurFunction()->markSafeWeakUse(RefExpr); |
849 | 1.01k | } |
850 | 1.39k | |
851 | 1.39k | return result; |
852 | 1.39k | } |
853 | | |
854 | | /// Try to build this as a call to a getter that returns a reference. |
855 | | /// |
856 | | /// \return true if it was possible, whether or not it actually |
857 | | /// succeeded |
858 | | bool ObjCPropertyOpBuilder::tryBuildGetOfReference(Expr *op, |
859 | 13 | ExprResult &result) { |
860 | 13 | if (!S.getLangOpts().CPlusPlus13 ) return false8 ; |
861 | 5 | |
862 | 5 | findGetter(); |
863 | 5 | if (!Getter5 ) { |
864 | 0 | // The property has no setter and no getter! This can happen if the type is |
865 | 0 | // invalid. Error have already been reported. |
866 | 0 | result = ExprError(); |
867 | 0 | return true; |
868 | 0 | } |
869 | 5 | |
870 | 5 | // Only do this if the getter returns an l-value reference type. |
871 | 5 | QualType resultType = Getter->getReturnType(); |
872 | 5 | if (!resultType->isLValueReferenceType()5 ) return false1 ; |
873 | 4 | |
874 | 4 | result = buildRValueOperation(op); |
875 | 4 | return true; |
876 | 4 | } |
877 | | |
878 | | /// @property-specific behavior for doing assignments. |
879 | | ExprResult |
880 | | ObjCPropertyOpBuilder::buildAssignmentOperation(Scope *Sc, |
881 | | SourceLocation opcLoc, |
882 | | BinaryOperatorKind opcode, |
883 | 752 | Expr *LHS, Expr *RHS) { |
884 | 752 | assert(BinaryOperator::isAssignmentOp(opcode)); |
885 | 752 | |
886 | 752 | // If there's no setter, we have no choice but to try to assign to |
887 | 752 | // the result of the getter. |
888 | 752 | if (!findSetter()752 ) { |
889 | 11 | ExprResult result; |
890 | 11 | if (tryBuildGetOfReference(LHS, result)11 ) { |
891 | 4 | if (result.isInvalid()4 ) return ExprError()0 ; |
892 | 4 | return S.BuildBinOp(Sc, opcLoc, opcode, result.get(), RHS); |
893 | 4 | } |
894 | 7 | |
895 | 7 | // Otherwise, it's an error. |
896 | 7 | S.Diag(opcLoc, diag::err_nosetter_property_assignment) |
897 | 7 | << unsigned(RefExpr->isImplicitProperty()) |
898 | 7 | << SetterSelector |
899 | 7 | << LHS->getSourceRange() << RHS->getSourceRange(); |
900 | 7 | return ExprError(); |
901 | 7 | } |
902 | 741 | |
903 | 741 | // If there is a setter, we definitely want to use it. |
904 | 741 | |
905 | 741 | // Verify that we can do a compound assignment. |
906 | 741 | if (741 opcode != BO_Assign && 741 !findGetter()27 ) { |
907 | 0 | S.Diag(opcLoc, diag::err_nogetter_property_compound_assignment) |
908 | 0 | << LHS->getSourceRange() << RHS->getSourceRange(); |
909 | 0 | return ExprError(); |
910 | 0 | } |
911 | 741 | |
912 | 741 | ExprResult result = |
913 | 741 | PseudoOpBuilder::buildAssignmentOperation(Sc, opcLoc, opcode, LHS, RHS); |
914 | 741 | if (result.isInvalid()741 ) return ExprError()12 ; |
915 | 729 | |
916 | 729 | // Various warnings about property assignments in ARC. |
917 | 729 | if (729 S.getLangOpts().ObjCAutoRefCount && 729 InstanceReceiver145 ) { |
918 | 137 | S.checkRetainCycles(InstanceReceiver->getSourceExpr(), RHS); |
919 | 137 | S.checkUnsafeExprAssigns(opcLoc, LHS, RHS); |
920 | 137 | } |
921 | 752 | |
922 | 752 | return result; |
923 | 752 | } |
924 | | |
925 | | /// @property-specific behavior for doing increments and decrements. |
926 | | ExprResult |
927 | | ObjCPropertyOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc, |
928 | | UnaryOperatorKind opcode, |
929 | 27 | Expr *op) { |
930 | 27 | // If there's no setter, we have no choice but to try to assign to |
931 | 27 | // the result of the getter. |
932 | 27 | if (!findSetter()27 ) { |
933 | 2 | ExprResult result; |
934 | 2 | if (tryBuildGetOfReference(op, result)2 ) { |
935 | 0 | if (result.isInvalid()0 ) return ExprError()0 ; |
936 | 0 | return S.BuildUnaryOp(Sc, opcLoc, opcode, result.get()); |
937 | 0 | } |
938 | 2 | |
939 | 2 | // Otherwise, it's an error. |
940 | 2 | S.Diag(opcLoc, diag::err_nosetter_property_incdec) |
941 | 2 | << unsigned(RefExpr->isImplicitProperty()) |
942 | 2 | << unsigned(UnaryOperator::isDecrementOp(opcode)) |
943 | 2 | << SetterSelector |
944 | 2 | << op->getSourceRange(); |
945 | 2 | return ExprError(); |
946 | 2 | } |
947 | 25 | |
948 | 25 | // If there is a setter, we definitely want to use it. |
949 | 25 | |
950 | 25 | // We also need a getter. |
951 | 25 | if (25 !findGetter()25 ) { |
952 | 2 | assert(RefExpr->isImplicitProperty()); |
953 | 2 | S.Diag(opcLoc, diag::err_nogetter_property_incdec) |
954 | 2 | << unsigned(UnaryOperator::isDecrementOp(opcode)) |
955 | 2 | << GetterSelector |
956 | 2 | << op->getSourceRange(); |
957 | 2 | return ExprError(); |
958 | 2 | } |
959 | 23 | |
960 | 23 | return PseudoOpBuilder::buildIncDecOperation(Sc, opcLoc, opcode, op); |
961 | 23 | } |
962 | | |
963 | 2.13k | ExprResult ObjCPropertyOpBuilder::complete(Expr *SyntacticForm) { |
964 | 2.13k | if (isWeakProperty() && |
965 | 212 | !S.Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, |
966 | 212 | SyntacticForm->getLocStart())) |
967 | 204 | S.recordUseOfEvaluatedWeak(SyntacticRefExpr, |
968 | 204 | SyntacticRefExpr->isMessagingGetter()); |
969 | 2.13k | |
970 | 2.13k | return PseudoOpBuilder::complete(SyntacticForm); |
971 | 2.13k | } |
972 | | |
973 | | // ObjCSubscript build stuff. |
974 | | // |
975 | | |
976 | | /// objective-c subscripting-specific behavior for doing lvalue-to-rvalue |
977 | | /// conversion. |
978 | | /// FIXME. Remove this routine if it is proven that no additional |
979 | | /// specifity is needed. |
980 | 146 | ExprResult ObjCSubscriptOpBuilder::buildRValueOperation(Expr *op) { |
981 | 146 | ExprResult result = PseudoOpBuilder::buildRValueOperation(op); |
982 | 146 | if (result.isInvalid()146 ) return ExprError()22 ; |
983 | 124 | return result; |
984 | 124 | } |
985 | | |
986 | | /// objective-c subscripting-specific behavior for doing assignments. |
987 | | ExprResult |
988 | | ObjCSubscriptOpBuilder::buildAssignmentOperation(Scope *Sc, |
989 | | SourceLocation opcLoc, |
990 | | BinaryOperatorKind opcode, |
991 | 112 | Expr *LHS, Expr *RHS) { |
992 | 112 | assert(BinaryOperator::isAssignmentOp(opcode)); |
993 | 112 | // There must be a method to do the Index'ed assignment. |
994 | 112 | if (!findAtIndexSetter()) |
995 | 14 | return ExprError(); |
996 | 98 | |
997 | 98 | // Verify that we can do a compound assignment. |
998 | 98 | if (98 opcode != BO_Assign && 98 !findAtIndexGetter()0 ) |
999 | 0 | return ExprError(); |
1000 | 98 | |
1001 | 98 | ExprResult result = |
1002 | 98 | PseudoOpBuilder::buildAssignmentOperation(Sc, opcLoc, opcode, LHS, RHS); |
1003 | 98 | if (result.isInvalid()98 ) return ExprError()7 ; |
1004 | 91 | |
1005 | 91 | // Various warnings about objc Index'ed assignments in ARC. |
1006 | 91 | if (91 S.getLangOpts().ObjCAutoRefCount && 91 InstanceBase6 ) { |
1007 | 6 | S.checkRetainCycles(InstanceBase->getSourceExpr(), RHS); |
1008 | 6 | S.checkUnsafeExprAssigns(opcLoc, LHS, RHS); |
1009 | 6 | } |
1010 | 112 | |
1011 | 112 | return result; |
1012 | 112 | } |
1013 | | |
1014 | | /// Capture the base object of an Objective-C Index'ed expression. |
1015 | 244 | Expr *ObjCSubscriptOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) { |
1016 | 244 | assert(InstanceBase == nullptr); |
1017 | 244 | |
1018 | 244 | // Capture base expression in an OVE and rebuild the syntactic |
1019 | 244 | // form to use the OVE as its base expression. |
1020 | 244 | InstanceBase = capture(RefExpr->getBaseExpr()); |
1021 | 244 | InstanceKey = capture(RefExpr->getKeyExpr()); |
1022 | 244 | |
1023 | 244 | syntacticBase = |
1024 | 488 | Rebuilder(S, [=](Expr *, unsigned Idx) -> Expr * { |
1025 | 488 | switch (Idx) { |
1026 | 244 | case 0: |
1027 | 244 | return InstanceBase; |
1028 | 244 | case 1: |
1029 | 244 | return InstanceKey; |
1030 | 0 | default: |
1031 | 0 | llvm_unreachable("Unexpected index for ObjCSubscriptExpr"); |
1032 | 0 | } |
1033 | 0 | }).rebuild(syntacticBase); |
1034 | 244 | |
1035 | 244 | return syntacticBase; |
1036 | 244 | } |
1037 | | |
1038 | | /// CheckSubscriptingKind - This routine decide what type |
1039 | | /// of indexing represented by "FromE" is being done. |
1040 | | Sema::ObjCSubscriptKind |
1041 | 259 | Sema::CheckSubscriptingKind(Expr *FromE) { |
1042 | 259 | // If the expression already has integral or enumeration type, we're golden. |
1043 | 259 | QualType T = FromE->getType(); |
1044 | 259 | if (T->isIntegralOrEnumerationType()) |
1045 | 129 | return OS_Array; |
1046 | 130 | |
1047 | 130 | // If we don't have a class type in C++, there's no way we can get an |
1048 | 130 | // expression of integral or enumeration type. |
1049 | 130 | const RecordType *RecordTy = T->getAs<RecordType>(); |
1050 | 130 | if (!RecordTy && |
1051 | 122 | (T->isObjCObjectPointerType() || 122 T->isVoidPointerType()24 )) |
1052 | 130 | // All other scalar cases are assumed to be dictionary indexing which |
1053 | 130 | // caller handles, with diagnostics if needed. |
1054 | 106 | return OS_Dictionary; |
1055 | 24 | if (24 !getLangOpts().CPlusPlus || |
1056 | 24 | !RecordTy10 || RecordTy->isIncompleteType()8 ) { |
1057 | 16 | // No indexing can be done. Issue diagnostics and quit. |
1058 | 16 | const Expr *IndexExpr = FromE->IgnoreParenImpCasts(); |
1059 | 16 | if (isa<StringLiteral>(IndexExpr)) |
1060 | 2 | Diag(FromE->getExprLoc(), diag::err_objc_subscript_pointer) |
1061 | 2 | << T << FixItHint::CreateInsertion(FromE->getExprLoc(), "@"); |
1062 | 16 | else |
1063 | 14 | Diag(FromE->getExprLoc(), diag::err_objc_subscript_type_conversion) |
1064 | 14 | << T; |
1065 | 16 | return OS_Error; |
1066 | 16 | } |
1067 | 8 | |
1068 | 8 | // We must have a complete class type. |
1069 | 8 | if (8 RequireCompleteType(FromE->getExprLoc(), T, |
1070 | 8 | diag::err_objc_index_incomplete_class_type, FromE)) |
1071 | 0 | return OS_Error; |
1072 | 8 | |
1073 | 8 | // Look for a conversion to an integral, enumeration type, or |
1074 | 8 | // objective-C pointer type. |
1075 | 8 | int NoIntegrals=0, NoObjCIdPointers=0; |
1076 | 8 | SmallVector<CXXConversionDecl *, 4> ConversionDecls; |
1077 | 8 | |
1078 | 8 | for (NamedDecl *D : cast<CXXRecordDecl>(RecordTy->getDecl()) |
1079 | 9 | ->getVisibleConversionFunctions()) { |
1080 | 9 | if (CXXConversionDecl *Conversion = |
1081 | 9 | dyn_cast<CXXConversionDecl>(D->getUnderlyingDecl())) { |
1082 | 9 | QualType CT = Conversion->getConversionType().getNonReferenceType(); |
1083 | 9 | if (CT->isIntegralOrEnumerationType()9 ) { |
1084 | 2 | ++NoIntegrals; |
1085 | 2 | ConversionDecls.push_back(Conversion); |
1086 | 2 | } |
1087 | 7 | else if (7 CT->isObjCIdType() ||7 CT->isBlockPointerType()4 ) { |
1088 | 7 | ++NoObjCIdPointers; |
1089 | 7 | ConversionDecls.push_back(Conversion); |
1090 | 7 | } |
1091 | 9 | } |
1092 | 9 | } |
1093 | 8 | if (NoIntegrals ==1 && 8 NoObjCIdPointers == 02 ) |
1094 | 1 | return OS_Array; |
1095 | 7 | if (7 NoIntegrals == 0 && 7 NoObjCIdPointers == 16 ) |
1096 | 6 | return OS_Dictionary; |
1097 | 1 | if (1 NoIntegrals == 0 && 1 NoObjCIdPointers == 00 ) { |
1098 | 0 | // No conversion function was found. Issue diagnostic and return. |
1099 | 0 | Diag(FromE->getExprLoc(), diag::err_objc_subscript_type_conversion) |
1100 | 0 | << FromE->getType(); |
1101 | 0 | return OS_Error; |
1102 | 0 | } |
1103 | 1 | Diag(FromE->getExprLoc(), diag::err_objc_multiple_subscript_type_conversion) |
1104 | 1 | << FromE->getType(); |
1105 | 3 | for (unsigned int i = 0; i < ConversionDecls.size()3 ; i++2 ) |
1106 | 2 | Diag(ConversionDecls[i]->getLocation(), |
1107 | 2 | diag::note_conv_function_declared_at); |
1108 | 259 | |
1109 | 259 | return OS_Error; |
1110 | 259 | } |
1111 | | |
1112 | | /// CheckKeyForObjCARCConversion - This routine suggests bridge casting of CF |
1113 | | /// objects used as dictionary subscript key objects. |
1114 | | static void CheckKeyForObjCARCConversion(Sema &S, QualType ContainerT, |
1115 | 4 | Expr *Key) { |
1116 | 4 | if (ContainerT.isNull()) |
1117 | 0 | return; |
1118 | 4 | // dictionary subscripting. |
1119 | 4 | // - (id)objectForKeyedSubscript:(id)key; |
1120 | 4 | IdentifierInfo *KeyIdents[] = { |
1121 | 4 | &S.Context.Idents.get("objectForKeyedSubscript") |
1122 | 4 | }; |
1123 | 4 | Selector GetterSelector = S.Context.Selectors.getSelector(1, KeyIdents); |
1124 | 4 | ObjCMethodDecl *Getter = S.LookupMethodInObjectType(GetterSelector, ContainerT, |
1125 | 4 | true /*instance*/); |
1126 | 4 | if (!Getter) |
1127 | 0 | return; |
1128 | 4 | QualType T = Getter->parameters()[0]->getType(); |
1129 | 4 | S.CheckObjCConversion(Key->getSourceRange(), T, Key, |
1130 | 4 | Sema::CCK_ImplicitConversion); |
1131 | 4 | } |
1132 | | |
1133 | 146 | bool ObjCSubscriptOpBuilder::findAtIndexGetter() { |
1134 | 146 | if (AtIndexGetter) |
1135 | 0 | return true; |
1136 | 146 | |
1137 | 146 | Expr *BaseExpr = RefExpr->getBaseExpr(); |
1138 | 146 | QualType BaseT = BaseExpr->getType(); |
1139 | 146 | |
1140 | 146 | QualType ResultType; |
1141 | 146 | if (const ObjCObjectPointerType *PTy = |
1142 | 146 | BaseT->getAs<ObjCObjectPointerType>()) { |
1143 | 146 | ResultType = PTy->getPointeeType(); |
1144 | 146 | } |
1145 | 146 | Sema::ObjCSubscriptKind Res = |
1146 | 146 | S.CheckSubscriptingKind(RefExpr->getKeyExpr()); |
1147 | 146 | if (Res == Sema::OS_Error146 ) { |
1148 | 11 | if (S.getLangOpts().ObjCAutoRefCount) |
1149 | 2 | CheckKeyForObjCARCConversion(S, ResultType, |
1150 | 2 | RefExpr->getKeyExpr()); |
1151 | 11 | return false; |
1152 | 11 | } |
1153 | 135 | bool arrayRef = (Res == Sema::OS_Array); |
1154 | 135 | |
1155 | 135 | if (ResultType.isNull()135 ) { |
1156 | 0 | S.Diag(BaseExpr->getExprLoc(), diag::err_objc_subscript_base_type) |
1157 | 0 | << BaseExpr->getType() << arrayRef; |
1158 | 0 | return false; |
1159 | 0 | } |
1160 | 135 | if (135 !arrayRef135 ) { |
1161 | 59 | // dictionary subscripting. |
1162 | 59 | // - (id)objectForKeyedSubscript:(id)key; |
1163 | 59 | IdentifierInfo *KeyIdents[] = { |
1164 | 59 | &S.Context.Idents.get("objectForKeyedSubscript") |
1165 | 59 | }; |
1166 | 59 | AtIndexGetterSelector = S.Context.Selectors.getSelector(1, KeyIdents); |
1167 | 59 | } |
1168 | 76 | else { |
1169 | 76 | // - (id)objectAtIndexedSubscript:(size_t)index; |
1170 | 76 | IdentifierInfo *KeyIdents[] = { |
1171 | 76 | &S.Context.Idents.get("objectAtIndexedSubscript") |
1172 | 76 | }; |
1173 | 76 | |
1174 | 76 | AtIndexGetterSelector = S.Context.Selectors.getSelector(1, KeyIdents); |
1175 | 76 | } |
1176 | 135 | |
1177 | 135 | AtIndexGetter = S.LookupMethodInObjectType(AtIndexGetterSelector, ResultType, |
1178 | 135 | true /*instance*/); |
1179 | 135 | |
1180 | 135 | if (!AtIndexGetter && 135 S.getLangOpts().DebuggerObjCLiteral17 ) { |
1181 | 0 | AtIndexGetter = ObjCMethodDecl::Create(S.Context, SourceLocation(), |
1182 | 0 | SourceLocation(), AtIndexGetterSelector, |
1183 | 0 | S.Context.getObjCIdType() /*ReturnType*/, |
1184 | 0 | nullptr /*TypeSourceInfo */, |
1185 | 0 | S.Context.getTranslationUnitDecl(), |
1186 | 0 | true /*Instance*/, false/*isVariadic*/, |
1187 | 0 | /*isPropertyAccessor=*/false, |
1188 | 0 | /*isImplicitlyDeclared=*/true, /*isDefined=*/false, |
1189 | 0 | ObjCMethodDecl::Required, |
1190 | 0 | false); |
1191 | 0 | ParmVarDecl *Argument = ParmVarDecl::Create(S.Context, AtIndexGetter, |
1192 | 0 | SourceLocation(), SourceLocation(), |
1193 | 0 | arrayRef ? &S.Context.Idents.get("index") |
1194 | 0 | : &S.Context.Idents.get("key"), |
1195 | 0 | arrayRef ? S.Context.UnsignedLongTy |
1196 | 0 | : S.Context.getObjCIdType(), |
1197 | 0 | /*TInfo=*/nullptr, |
1198 | 0 | SC_None, |
1199 | 0 | nullptr); |
1200 | 0 | AtIndexGetter->setMethodParams(S.Context, Argument, None); |
1201 | 0 | } |
1202 | 135 | |
1203 | 135 | if (!AtIndexGetter135 ) { |
1204 | 17 | if (!BaseT->isObjCIdType()17 ) { |
1205 | 7 | S.Diag(BaseExpr->getExprLoc(), diag::err_objc_subscript_method_not_found) |
1206 | 7 | << BaseExpr->getType() << 0 << arrayRef; |
1207 | 7 | return false; |
1208 | 7 | } |
1209 | 10 | AtIndexGetter = |
1210 | 10 | S.LookupInstanceMethodInGlobalPool(AtIndexGetterSelector, |
1211 | 10 | RefExpr->getSourceRange(), |
1212 | 10 | true); |
1213 | 10 | } |
1214 | 135 | |
1215 | 128 | if (128 AtIndexGetter128 ) { |
1216 | 127 | QualType T = AtIndexGetter->parameters()[0]->getType(); |
1217 | 127 | if ((arrayRef && 127 !T->isIntegralOrEnumerationType()69 ) || |
1218 | 127 | (!arrayRef && 126 !T->isObjCObjectPointerType()58 )) { |
1219 | 2 | S.Diag(RefExpr->getKeyExpr()->getExprLoc(), |
1220 | 1 | arrayRef ? diag::err_objc_subscript_index_type |
1221 | 1 | : diag::err_objc_subscript_key_type) << T; |
1222 | 2 | S.Diag(AtIndexGetter->parameters()[0]->getLocation(), |
1223 | 2 | diag::note_parameter_type) << T; |
1224 | 2 | return false; |
1225 | 2 | } |
1226 | 125 | QualType R = AtIndexGetter->getReturnType(); |
1227 | 125 | if (!R->isObjCObjectPointerType()125 ) { |
1228 | 2 | S.Diag(RefExpr->getKeyExpr()->getExprLoc(), |
1229 | 2 | diag::err_objc_indexing_method_result_type) << R << arrayRef; |
1230 | 2 | S.Diag(AtIndexGetter->getLocation(), diag::note_method_declared_at) << |
1231 | 2 | AtIndexGetter->getDeclName(); |
1232 | 2 | } |
1233 | 127 | } |
1234 | 126 | return true; |
1235 | 146 | } |
1236 | | |
1237 | 210 | bool ObjCSubscriptOpBuilder::findAtIndexSetter() { |
1238 | 210 | if (AtIndexSetter) |
1239 | 97 | return true; |
1240 | 113 | |
1241 | 113 | Expr *BaseExpr = RefExpr->getBaseExpr(); |
1242 | 113 | QualType BaseT = BaseExpr->getType(); |
1243 | 113 | |
1244 | 113 | QualType ResultType; |
1245 | 113 | if (const ObjCObjectPointerType *PTy = |
1246 | 113 | BaseT->getAs<ObjCObjectPointerType>()) { |
1247 | 113 | ResultType = PTy->getPointeeType(); |
1248 | 113 | } |
1249 | 113 | |
1250 | 113 | Sema::ObjCSubscriptKind Res = |
1251 | 113 | S.CheckSubscriptingKind(RefExpr->getKeyExpr()); |
1252 | 113 | if (Res == Sema::OS_Error113 ) { |
1253 | 6 | if (S.getLangOpts().ObjCAutoRefCount) |
1254 | 2 | CheckKeyForObjCARCConversion(S, ResultType, |
1255 | 2 | RefExpr->getKeyExpr()); |
1256 | 6 | return false; |
1257 | 6 | } |
1258 | 107 | bool arrayRef = (Res == Sema::OS_Array); |
1259 | 107 | |
1260 | 107 | if (ResultType.isNull()107 ) { |
1261 | 0 | S.Diag(BaseExpr->getExprLoc(), diag::err_objc_subscript_base_type) |
1262 | 0 | << BaseExpr->getType() << arrayRef; |
1263 | 0 | return false; |
1264 | 0 | } |
1265 | 107 | |
1266 | 107 | if (107 !arrayRef107 ) { |
1267 | 53 | // dictionary subscripting. |
1268 | 53 | // - (void)setObject:(id)object forKeyedSubscript:(id)key; |
1269 | 53 | IdentifierInfo *KeyIdents[] = { |
1270 | 53 | &S.Context.Idents.get("setObject"), |
1271 | 53 | &S.Context.Idents.get("forKeyedSubscript") |
1272 | 53 | }; |
1273 | 53 | AtIndexSetterSelector = S.Context.Selectors.getSelector(2, KeyIdents); |
1274 | 53 | } |
1275 | 54 | else { |
1276 | 54 | // - (void)setObject:(id)object atIndexedSubscript:(NSInteger)index; |
1277 | 54 | IdentifierInfo *KeyIdents[] = { |
1278 | 54 | &S.Context.Idents.get("setObject"), |
1279 | 54 | &S.Context.Idents.get("atIndexedSubscript") |
1280 | 54 | }; |
1281 | 54 | AtIndexSetterSelector = S.Context.Selectors.getSelector(2, KeyIdents); |
1282 | 54 | } |
1283 | 107 | AtIndexSetter = S.LookupMethodInObjectType(AtIndexSetterSelector, ResultType, |
1284 | 107 | true /*instance*/); |
1285 | 107 | |
1286 | 107 | if (!AtIndexSetter && 107 S.getLangOpts().DebuggerObjCLiteral11 ) { |
1287 | 0 | TypeSourceInfo *ReturnTInfo = nullptr; |
1288 | 0 | QualType ReturnType = S.Context.VoidTy; |
1289 | 0 | AtIndexSetter = ObjCMethodDecl::Create( |
1290 | 0 | S.Context, SourceLocation(), SourceLocation(), AtIndexSetterSelector, |
1291 | 0 | ReturnType, ReturnTInfo, S.Context.getTranslationUnitDecl(), |
1292 | 0 | true /*Instance*/, false /*isVariadic*/, |
1293 | 0 | /*isPropertyAccessor=*/false, |
1294 | 0 | /*isImplicitlyDeclared=*/true, /*isDefined=*/false, |
1295 | 0 | ObjCMethodDecl::Required, false); |
1296 | 0 | SmallVector<ParmVarDecl *, 2> Params; |
1297 | 0 | ParmVarDecl *object = ParmVarDecl::Create(S.Context, AtIndexSetter, |
1298 | 0 | SourceLocation(), SourceLocation(), |
1299 | 0 | &S.Context.Idents.get("object"), |
1300 | 0 | S.Context.getObjCIdType(), |
1301 | 0 | /*TInfo=*/nullptr, |
1302 | 0 | SC_None, |
1303 | 0 | nullptr); |
1304 | 0 | Params.push_back(object); |
1305 | 0 | ParmVarDecl *key = ParmVarDecl::Create(S.Context, AtIndexSetter, |
1306 | 0 | SourceLocation(), SourceLocation(), |
1307 | 0 | arrayRef ? &S.Context.Idents.get("index") |
1308 | 0 | : &S.Context.Idents.get("key"), |
1309 | 0 | arrayRef ? S.Context.UnsignedLongTy |
1310 | 0 | : S.Context.getObjCIdType(), |
1311 | 0 | /*TInfo=*/nullptr, |
1312 | 0 | SC_None, |
1313 | 0 | nullptr); |
1314 | 0 | Params.push_back(key); |
1315 | 0 | AtIndexSetter->setMethodParams(S.Context, Params, None); |
1316 | 0 | } |
1317 | 107 | |
1318 | 107 | if (!AtIndexSetter107 ) { |
1319 | 11 | if (!BaseT->isObjCIdType()11 ) { |
1320 | 4 | S.Diag(BaseExpr->getExprLoc(), |
1321 | 4 | diag::err_objc_subscript_method_not_found) |
1322 | 4 | << BaseExpr->getType() << 1 << arrayRef; |
1323 | 4 | return false; |
1324 | 4 | } |
1325 | 7 | AtIndexSetter = |
1326 | 7 | S.LookupInstanceMethodInGlobalPool(AtIndexSetterSelector, |
1327 | 7 | RefExpr->getSourceRange(), |
1328 | 7 | true); |
1329 | 7 | } |
1330 | 107 | |
1331 | 103 | bool err = false; |
1332 | 103 | if (AtIndexSetter && 103 arrayRef101 ) { |
1333 | 48 | QualType T = AtIndexSetter->parameters()[1]->getType(); |
1334 | 48 | if (!T->isIntegralOrEnumerationType()48 ) { |
1335 | 1 | S.Diag(RefExpr->getKeyExpr()->getExprLoc(), |
1336 | 1 | diag::err_objc_subscript_index_type) << T; |
1337 | 1 | S.Diag(AtIndexSetter->parameters()[1]->getLocation(), |
1338 | 1 | diag::note_parameter_type) << T; |
1339 | 1 | err = true; |
1340 | 1 | } |
1341 | 48 | T = AtIndexSetter->parameters()[0]->getType(); |
1342 | 48 | if (!T->isObjCObjectPointerType()48 ) { |
1343 | 2 | S.Diag(RefExpr->getBaseExpr()->getExprLoc(), |
1344 | 2 | diag::err_objc_subscript_object_type) << T << arrayRef; |
1345 | 2 | S.Diag(AtIndexSetter->parameters()[0]->getLocation(), |
1346 | 2 | diag::note_parameter_type) << T; |
1347 | 2 | err = true; |
1348 | 2 | } |
1349 | 48 | } |
1350 | 55 | else if (55 AtIndexSetter && 55 !arrayRef53 ) |
1351 | 159 | for (unsigned i=0; 53 i <2159 ; i++106 ) { |
1352 | 106 | QualType T = AtIndexSetter->parameters()[i]->getType(); |
1353 | 106 | if (!T->isObjCObjectPointerType()106 ) { |
1354 | 3 | if (i == 1) |
1355 | 1 | S.Diag(RefExpr->getKeyExpr()->getExprLoc(), |
1356 | 1 | diag::err_objc_subscript_key_type) << T; |
1357 | 3 | else |
1358 | 2 | S.Diag(RefExpr->getBaseExpr()->getExprLoc(), |
1359 | 2 | diag::err_objc_subscript_dic_object_type) << T; |
1360 | 3 | S.Diag(AtIndexSetter->parameters()[i]->getLocation(), |
1361 | 3 | diag::note_parameter_type) << T; |
1362 | 3 | err = true; |
1363 | 3 | } |
1364 | 55 | } |
1365 | 103 | |
1366 | 103 | return !err; |
1367 | 210 | } |
1368 | | |
1369 | | // Get the object at "Index" position in the container. |
1370 | | // [BaseExpr objectAtIndexedSubscript : IndexExpr]; |
1371 | 146 | ExprResult ObjCSubscriptOpBuilder::buildGet() { |
1372 | 146 | if (!findAtIndexGetter()) |
1373 | 20 | return ExprError(); |
1374 | 126 | |
1375 | 126 | QualType receiverType = InstanceBase->getType(); |
1376 | 126 | |
1377 | 126 | // Build a message-send. |
1378 | 126 | ExprResult msg; |
1379 | 126 | Expr *Index = InstanceKey; |
1380 | 126 | |
1381 | 126 | // Arguments. |
1382 | 126 | Expr *args[] = { Index }; |
1383 | 126 | assert(InstanceBase); |
1384 | 126 | if (AtIndexGetter) |
1385 | 125 | S.DiagnoseUseOfDecl(AtIndexGetter, GenericLoc); |
1386 | 146 | msg = S.BuildInstanceMessageImplicit(InstanceBase, receiverType, |
1387 | 146 | GenericLoc, |
1388 | 146 | AtIndexGetterSelector, AtIndexGetter, |
1389 | 146 | MultiExprArg(args, 1)); |
1390 | 146 | return msg; |
1391 | 146 | } |
1392 | | |
1393 | | /// Store into the container the "op" object at "Index"'ed location |
1394 | | /// by building this messaging expression: |
1395 | | /// - (void)setObject:(id)object atIndexedSubscript:(NSInteger)index; |
1396 | | /// \param captureSetValueAsResult If true, capture the actual |
1397 | | /// value being set as the value of the property operation. |
1398 | | ExprResult ObjCSubscriptOpBuilder::buildSet(Expr *op, SourceLocation opcLoc, |
1399 | 98 | bool captureSetValueAsResult) { |
1400 | 98 | if (!findAtIndexSetter()) |
1401 | 0 | return ExprError(); |
1402 | 98 | if (98 AtIndexSetter98 ) |
1403 | 97 | S.DiagnoseUseOfDecl(AtIndexSetter, GenericLoc); |
1404 | 98 | QualType receiverType = InstanceBase->getType(); |
1405 | 98 | Expr *Index = InstanceKey; |
1406 | 98 | |
1407 | 98 | // Arguments. |
1408 | 98 | Expr *args[] = { op, Index }; |
1409 | 98 | |
1410 | 98 | // Build a message-send. |
1411 | 98 | ExprResult msg = S.BuildInstanceMessageImplicit(InstanceBase, receiverType, |
1412 | 98 | GenericLoc, |
1413 | 98 | AtIndexSetterSelector, |
1414 | 98 | AtIndexSetter, |
1415 | 98 | MultiExprArg(args, 2)); |
1416 | 98 | |
1417 | 98 | if (!msg.isInvalid() && 98 captureSetValueAsResult91 ) { |
1418 | 91 | ObjCMessageExpr *msgExpr = |
1419 | 91 | cast<ObjCMessageExpr>(msg.get()->IgnoreImplicit()); |
1420 | 91 | Expr *arg = msgExpr->getArg(0); |
1421 | 91 | if (CanCaptureValue(arg)) |
1422 | 91 | msgExpr->setArg(0, captureValueAsResult(arg)); |
1423 | 91 | } |
1424 | 98 | |
1425 | 98 | return msg; |
1426 | 98 | } |
1427 | | |
1428 | | //===----------------------------------------------------------------------===// |
1429 | | // MSVC __declspec(property) references |
1430 | | //===----------------------------------------------------------------------===// |
1431 | | |
1432 | | MSPropertyRefExpr * |
1433 | 72 | MSPropertyOpBuilder::getBaseMSProperty(MSPropertySubscriptExpr *E) { |
1434 | 72 | CallArgs.insert(CallArgs.begin(), E->getIdx()); |
1435 | 72 | Expr *Base = E->getBase()->IgnoreParens(); |
1436 | 144 | while (auto *MSPropSubscript144 = dyn_cast<MSPropertySubscriptExpr>(Base)) { |
1437 | 72 | CallArgs.insert(CallArgs.begin(), MSPropSubscript->getIdx()); |
1438 | 72 | Base = MSPropSubscript->getBase()->IgnoreParens(); |
1439 | 72 | } |
1440 | 72 | return cast<MSPropertyRefExpr>(Base); |
1441 | 72 | } |
1442 | | |
1443 | 247 | Expr *MSPropertyOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) { |
1444 | 247 | InstanceBase = capture(RefExpr->getBaseExpr()); |
1445 | 247 | std::for_each(CallArgs.begin(), CallArgs.end(), |
1446 | 144 | [this](Expr *&Arg) { Arg = capture(Arg); }); |
1447 | 391 | syntacticBase = Rebuilder(S, [=](Expr *, unsigned Idx) -> Expr * { |
1448 | 391 | switch (Idx) { |
1449 | 247 | case 0: |
1450 | 247 | return InstanceBase; |
1451 | 144 | default: |
1452 | 144 | assert(Idx <= CallArgs.size()); |
1453 | 144 | return CallArgs[Idx - 1]; |
1454 | 0 | } |
1455 | 0 | }).rebuild(syntacticBase); |
1456 | 247 | |
1457 | 247 | return syntacticBase; |
1458 | 247 | } |
1459 | | |
1460 | 175 | ExprResult MSPropertyOpBuilder::buildGet() { |
1461 | 175 | if (!RefExpr->getPropertyDecl()->hasGetter()175 ) { |
1462 | 3 | S.Diag(RefExpr->getMemberLoc(), diag::err_no_accessor_for_property) |
1463 | 3 | << 0 /* getter */ << RefExpr->getPropertyDecl(); |
1464 | 3 | return ExprError(); |
1465 | 3 | } |
1466 | 172 | |
1467 | 172 | UnqualifiedId GetterName; |
1468 | 172 | IdentifierInfo *II = RefExpr->getPropertyDecl()->getGetterId(); |
1469 | 172 | GetterName.setIdentifier(II, RefExpr->getMemberLoc()); |
1470 | 172 | CXXScopeSpec SS; |
1471 | 172 | SS.Adopt(RefExpr->getQualifierLoc()); |
1472 | 172 | ExprResult GetterExpr = |
1473 | 172 | S.ActOnMemberAccessExpr(S.getCurScope(), InstanceBase, SourceLocation(), |
1474 | 172 | RefExpr->isArrow() ? tok::arrow92 : tok::period80 , SS, |
1475 | 172 | SourceLocation(), GetterName, nullptr); |
1476 | 172 | if (GetterExpr.isInvalid()172 ) { |
1477 | 3 | S.Diag(RefExpr->getMemberLoc(), |
1478 | 3 | diag::err_cannot_find_suitable_accessor) << 0 /* getter */ |
1479 | 3 | << RefExpr->getPropertyDecl(); |
1480 | 3 | return ExprError(); |
1481 | 3 | } |
1482 | 169 | |
1483 | 169 | return S.ActOnCallExpr(S.getCurScope(), GetterExpr.get(), |
1484 | 169 | RefExpr->getSourceRange().getBegin(), CallArgs, |
1485 | 169 | RefExpr->getSourceRange().getEnd()); |
1486 | 169 | } |
1487 | | |
1488 | | ExprResult MSPropertyOpBuilder::buildSet(Expr *op, SourceLocation sl, |
1489 | 99 | bool captureSetValueAsResult) { |
1490 | 99 | if (!RefExpr->getPropertyDecl()->hasSetter()99 ) { |
1491 | 16 | S.Diag(RefExpr->getMemberLoc(), diag::err_no_accessor_for_property) |
1492 | 16 | << 1 /* setter */ << RefExpr->getPropertyDecl(); |
1493 | 16 | return ExprError(); |
1494 | 16 | } |
1495 | 83 | |
1496 | 83 | UnqualifiedId SetterName; |
1497 | 83 | IdentifierInfo *II = RefExpr->getPropertyDecl()->getSetterId(); |
1498 | 83 | SetterName.setIdentifier(II, RefExpr->getMemberLoc()); |
1499 | 83 | CXXScopeSpec SS; |
1500 | 83 | SS.Adopt(RefExpr->getQualifierLoc()); |
1501 | 83 | ExprResult SetterExpr = |
1502 | 83 | S.ActOnMemberAccessExpr(S.getCurScope(), InstanceBase, SourceLocation(), |
1503 | 83 | RefExpr->isArrow() ? tok::arrow58 : tok::period25 , SS, |
1504 | 83 | SourceLocation(), SetterName, nullptr); |
1505 | 83 | if (SetterExpr.isInvalid()83 ) { |
1506 | 3 | S.Diag(RefExpr->getMemberLoc(), |
1507 | 3 | diag::err_cannot_find_suitable_accessor) << 1 /* setter */ |
1508 | 3 | << RefExpr->getPropertyDecl(); |
1509 | 3 | return ExprError(); |
1510 | 3 | } |
1511 | 80 | |
1512 | 80 | SmallVector<Expr*, 4> ArgExprs; |
1513 | 80 | ArgExprs.append(CallArgs.begin(), CallArgs.end()); |
1514 | 80 | ArgExprs.push_back(op); |
1515 | 80 | return S.ActOnCallExpr(S.getCurScope(), SetterExpr.get(), |
1516 | 80 | RefExpr->getSourceRange().getBegin(), ArgExprs, |
1517 | 80 | op->getSourceRange().getEnd()); |
1518 | 80 | } |
1519 | | |
1520 | | //===----------------------------------------------------------------------===// |
1521 | | // General Sema routines. |
1522 | | //===----------------------------------------------------------------------===// |
1523 | | |
1524 | 1.68k | ExprResult Sema::checkPseudoObjectRValue(Expr *E) { |
1525 | 1.68k | Expr *opaqueRef = E->IgnoreParens(); |
1526 | 1.68k | if (ObjCPropertyRefExpr *refExpr |
1527 | 1.38k | = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) { |
1528 | 1.38k | ObjCPropertyOpBuilder builder(*this, refExpr); |
1529 | 1.38k | return builder.buildRValueOperation(E); |
1530 | 1.38k | } |
1531 | 293 | else if (ObjCSubscriptRefExpr *293 refExpr293 |
1532 | 146 | = dyn_cast<ObjCSubscriptRefExpr>(opaqueRef)) { |
1533 | 146 | ObjCSubscriptOpBuilder builder(*this, refExpr); |
1534 | 146 | return builder.buildRValueOperation(E); |
1535 | 147 | } else if (MSPropertyRefExpr *147 refExpr147 |
1536 | 116 | = dyn_cast<MSPropertyRefExpr>(opaqueRef)) { |
1537 | 116 | MSPropertyOpBuilder builder(*this, refExpr); |
1538 | 116 | return builder.buildRValueOperation(E); |
1539 | 31 | } else if (MSPropertySubscriptExpr *31 RefExpr31 = |
1540 | 31 | dyn_cast<MSPropertySubscriptExpr>(opaqueRef)) { |
1541 | 31 | MSPropertyOpBuilder Builder(*this, RefExpr); |
1542 | 31 | return Builder.buildRValueOperation(E); |
1543 | 0 | } else { |
1544 | 0 | llvm_unreachable("unknown pseudo-object kind!"); |
1545 | 293 | } |
1546 | 0 | } |
1547 | | |
1548 | | /// Check an increment or decrement of a pseudo-object expression. |
1549 | | ExprResult Sema::checkPseudoObjectIncDec(Scope *Sc, SourceLocation opcLoc, |
1550 | 48 | UnaryOperatorKind opcode, Expr *op) { |
1551 | 48 | // Do nothing if the operand is dependent. |
1552 | 48 | if (op->isTypeDependent()) |
1553 | 0 | return new (Context) UnaryOperator(op, opcode, Context.DependentTy, |
1554 | 0 | VK_RValue, OK_Ordinary, opcLoc); |
1555 | 48 | |
1556 | 48 | assert(UnaryOperator::isIncrementDecrementOp(opcode)); |
1557 | 48 | Expr *opaqueRef = op->IgnoreParens(); |
1558 | 48 | if (ObjCPropertyRefExpr *refExpr |
1559 | 27 | = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) { |
1560 | 27 | ObjCPropertyOpBuilder builder(*this, refExpr); |
1561 | 27 | return builder.buildIncDecOperation(Sc, opcLoc, opcode, op); |
1562 | 21 | } else if (21 isa<ObjCSubscriptRefExpr>(opaqueRef)21 ) { |
1563 | 3 | Diag(opcLoc, diag::err_illegal_container_subscripting_op); |
1564 | 3 | return ExprError(); |
1565 | 18 | } else if (MSPropertyRefExpr *18 refExpr18 |
1566 | 11 | = dyn_cast<MSPropertyRefExpr>(opaqueRef)) { |
1567 | 11 | MSPropertyOpBuilder builder(*this, refExpr); |
1568 | 11 | return builder.buildIncDecOperation(Sc, opcLoc, opcode, op); |
1569 | 7 | } else if (MSPropertySubscriptExpr *7 RefExpr7 |
1570 | 7 | = dyn_cast<MSPropertySubscriptExpr>(opaqueRef)) { |
1571 | 7 | MSPropertyOpBuilder Builder(*this, RefExpr); |
1572 | 7 | return Builder.buildIncDecOperation(Sc, opcLoc, opcode, op); |
1573 | 0 | } else { |
1574 | 0 | llvm_unreachable("unknown pseudo-object kind!"); |
1575 | 21 | } |
1576 | 0 | } |
1577 | | |
1578 | | ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc, |
1579 | | BinaryOperatorKind opcode, |
1580 | 952 | Expr *LHS, Expr *RHS) { |
1581 | 952 | // Do nothing if either argument is dependent. |
1582 | 952 | if (LHS->isTypeDependent() || 952 RHS->isTypeDependent()952 ) |
1583 | 6 | return new (Context) BinaryOperator(LHS, RHS, opcode, Context.DependentTy, |
1584 | 6 | VK_RValue, OK_Ordinary, opcLoc, |
1585 | 6 | FPOptions()); |
1586 | 946 | |
1587 | 946 | // Filter out non-overload placeholder types in the RHS. |
1588 | 946 | if (946 RHS->getType()->isNonOverloadPlaceholderType()946 ) { |
1589 | 58 | ExprResult result = CheckPlaceholderExpr(RHS); |
1590 | 58 | if (result.isInvalid()58 ) return ExprError()0 ; |
1591 | 58 | RHS = result.get(); |
1592 | 58 | } |
1593 | 946 | |
1594 | 946 | Expr *opaqueRef = LHS->IgnoreParens(); |
1595 | 946 | if (ObjCPropertyRefExpr *refExpr |
1596 | 752 | = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) { |
1597 | 752 | ObjCPropertyOpBuilder builder(*this, refExpr); |
1598 | 752 | return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS); |
1599 | 194 | } else if (ObjCSubscriptRefExpr *194 refExpr194 |
1600 | 112 | = dyn_cast<ObjCSubscriptRefExpr>(opaqueRef)) { |
1601 | 112 | ObjCSubscriptOpBuilder builder(*this, refExpr); |
1602 | 112 | return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS); |
1603 | 82 | } else if (MSPropertyRefExpr *82 refExpr82 |
1604 | 48 | = dyn_cast<MSPropertyRefExpr>(opaqueRef)) { |
1605 | 48 | MSPropertyOpBuilder builder(*this, refExpr); |
1606 | 48 | return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS); |
1607 | 34 | } else if (MSPropertySubscriptExpr *34 RefExpr34 |
1608 | 34 | = dyn_cast<MSPropertySubscriptExpr>(opaqueRef)) { |
1609 | 34 | MSPropertyOpBuilder Builder(*this, RefExpr); |
1610 | 34 | return Builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS); |
1611 | 0 | } else { |
1612 | 0 | llvm_unreachable("unknown pseudo-object kind!"); |
1613 | 194 | } |
1614 | 0 | } |
1615 | | |
1616 | | /// Given a pseudo-object reference, rebuild it without the opaque |
1617 | | /// values. Basically, undo the behavior of rebuildAndCaptureObject. |
1618 | | /// This should never operate in-place. |
1619 | 40 | static Expr *stripOpaqueValuesFromPseudoObjectRef(Sema &S, Expr *E) { |
1620 | 40 | return Rebuilder(S, |
1621 | 65 | [=](Expr *E, unsigned) -> Expr * { |
1622 | 65 | return cast<OpaqueValueExpr>(E)->getSourceExpr(); |
1623 | 65 | }) |
1624 | 40 | .rebuild(E); |
1625 | 40 | } |
1626 | | |
1627 | | /// Given a pseudo-object expression, recreate what it looks like |
1628 | | /// syntactically without the attendant OpaqueValueExprs. |
1629 | | /// |
1630 | | /// This is a hack which should be removed when TreeTransform is |
1631 | | /// capable of rebuilding a tree without stripping implicit |
1632 | | /// operations. |
1633 | 40 | Expr *Sema::recreateSyntacticForm(PseudoObjectExpr *E) { |
1634 | 40 | Expr *syntax = E->getSyntacticForm(); |
1635 | 40 | if (UnaryOperator *uop40 = dyn_cast<UnaryOperator>(syntax)) { |
1636 | 4 | Expr *op = stripOpaqueValuesFromPseudoObjectRef(*this, uop->getSubExpr()); |
1637 | 4 | return new (Context) UnaryOperator(op, uop->getOpcode(), uop->getType(), |
1638 | 4 | uop->getValueKind(), uop->getObjectKind(), |
1639 | 4 | uop->getOperatorLoc()); |
1640 | 36 | } else if (CompoundAssignOperator *36 cop36 |
1641 | 5 | = dyn_cast<CompoundAssignOperator>(syntax)) { |
1642 | 5 | Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, cop->getLHS()); |
1643 | 5 | Expr *rhs = cast<OpaqueValueExpr>(cop->getRHS())->getSourceExpr(); |
1644 | 5 | return new (Context) CompoundAssignOperator(lhs, rhs, cop->getOpcode(), |
1645 | 5 | cop->getType(), |
1646 | 5 | cop->getValueKind(), |
1647 | 5 | cop->getObjectKind(), |
1648 | 5 | cop->getComputationLHSType(), |
1649 | 5 | cop->getComputationResultType(), |
1650 | 5 | cop->getOperatorLoc(), |
1651 | 5 | FPOptions()); |
1652 | 31 | } else if (BinaryOperator *31 bop31 = dyn_cast<BinaryOperator>(syntax)) { |
1653 | 13 | Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, bop->getLHS()); |
1654 | 13 | Expr *rhs = cast<OpaqueValueExpr>(bop->getRHS())->getSourceExpr(); |
1655 | 13 | return new (Context) BinaryOperator(lhs, rhs, bop->getOpcode(), |
1656 | 13 | bop->getType(), bop->getValueKind(), |
1657 | 13 | bop->getObjectKind(), |
1658 | 13 | bop->getOperatorLoc(), FPOptions()); |
1659 | 0 | } else { |
1660 | 18 | assert(syntax->hasPlaceholderType(BuiltinType::PseudoObject)); |
1661 | 18 | return stripOpaqueValuesFromPseudoObjectRef(*this, syntax); |
1662 | 18 | } |
1663 | 0 | } |