SemaPseudoObject.cpp revision ed7f727257b770b6db8a86a29590bb9cbeeb002f
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/Sema/Initialization.h" 35#include "clang/AST/ExprObjC.h" 36#include "clang/Lex/Preprocessor.h" 37 38using namespace clang; 39using namespace sema; 40 41namespace { 42 // Basically just a very focused copy of TreeTransform. 43 template <class T> struct Rebuilder { 44 Sema &S; 45 Rebuilder(Sema &S) : S(S) {} 46 47 T &getDerived() { return static_cast<T&>(*this); } 48 49 Expr *rebuild(Expr *e) { 50 // Fast path: nothing to look through. 51 if (typename T::specific_type *specific 52 = dyn_cast<typename T::specific_type>(e)) 53 return getDerived().rebuildSpecific(specific); 54 55 // Otherwise, we should look through and rebuild anything that 56 // IgnoreParens would. 57 58 if (ParenExpr *parens = dyn_cast<ParenExpr>(e)) { 59 e = rebuild(parens->getSubExpr()); 60 return new (S.Context) ParenExpr(parens->getLParen(), 61 parens->getRParen(), 62 e); 63 } 64 65 if (UnaryOperator *uop = dyn_cast<UnaryOperator>(e)) { 66 assert(uop->getOpcode() == UO_Extension); 67 e = rebuild(uop->getSubExpr()); 68 return new (S.Context) UnaryOperator(e, uop->getOpcode(), 69 uop->getType(), 70 uop->getValueKind(), 71 uop->getObjectKind(), 72 uop->getOperatorLoc()); 73 } 74 75 if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) { 76 assert(!gse->isResultDependent()); 77 unsigned resultIndex = gse->getResultIndex(); 78 unsigned numAssocs = gse->getNumAssocs(); 79 80 SmallVector<Expr*, 8> assocs(numAssocs); 81 SmallVector<TypeSourceInfo*, 8> assocTypes(numAssocs); 82 83 for (unsigned i = 0; i != numAssocs; ++i) { 84 Expr *assoc = gse->getAssocExpr(i); 85 if (i == resultIndex) assoc = rebuild(assoc); 86 assocs[i] = assoc; 87 assocTypes[i] = gse->getAssocTypeSourceInfo(i); 88 } 89 90 return new (S.Context) GenericSelectionExpr(S.Context, 91 gse->getGenericLoc(), 92 gse->getControllingExpr(), 93 assocTypes.data(), 94 assocs.data(), 95 numAssocs, 96 gse->getDefaultLoc(), 97 gse->getRParenLoc(), 98 gse->containsUnexpandedParameterPack(), 99 resultIndex); 100 } 101 102 llvm_unreachable("bad expression to rebuild!"); 103 } 104 }; 105 106 struct ObjCPropertyRefRebuilder : Rebuilder<ObjCPropertyRefRebuilder> { 107 Expr *NewBase; 108 ObjCPropertyRefRebuilder(Sema &S, Expr *newBase) 109 : Rebuilder<ObjCPropertyRefRebuilder>(S), NewBase(newBase) {} 110 111 typedef ObjCPropertyRefExpr specific_type; 112 Expr *rebuildSpecific(ObjCPropertyRefExpr *refExpr) { 113 // Fortunately, the constraint that we're rebuilding something 114 // with a base limits the number of cases here. 115 assert(refExpr->getBase()); 116 117 if (refExpr->isExplicitProperty()) { 118 return new (S.Context) 119 ObjCPropertyRefExpr(refExpr->getExplicitProperty(), 120 refExpr->getType(), refExpr->getValueKind(), 121 refExpr->getObjectKind(), refExpr->getLocation(), 122 NewBase); 123 } 124 return new (S.Context) 125 ObjCPropertyRefExpr(refExpr->getImplicitPropertyGetter(), 126 refExpr->getImplicitPropertySetter(), 127 refExpr->getType(), refExpr->getValueKind(), 128 refExpr->getObjectKind(),refExpr->getLocation(), 129 NewBase); 130 } 131 }; 132 133 class PseudoOpBuilder { 134 public: 135 Sema &S; 136 unsigned ResultIndex; 137 SourceLocation GenericLoc; 138 SmallVector<Expr *, 4> Semantics; 139 140 PseudoOpBuilder(Sema &S, SourceLocation genericLoc) 141 : S(S), ResultIndex(PseudoObjectExpr::NoResult), 142 GenericLoc(genericLoc) {} 143 144 virtual ~PseudoOpBuilder() {} 145 146 /// Add a normal semantic expression. 147 void addSemanticExpr(Expr *semantic) { 148 Semantics.push_back(semantic); 149 } 150 151 /// Add the 'result' semantic expression. 152 void addResultSemanticExpr(Expr *resultExpr) { 153 assert(ResultIndex == PseudoObjectExpr::NoResult); 154 ResultIndex = Semantics.size(); 155 Semantics.push_back(resultExpr); 156 } 157 158 ExprResult buildRValueOperation(Expr *op); 159 ExprResult buildAssignmentOperation(Scope *Sc, 160 SourceLocation opLoc, 161 BinaryOperatorKind opcode, 162 Expr *LHS, Expr *RHS); 163 ExprResult buildIncDecOperation(Scope *Sc, SourceLocation opLoc, 164 UnaryOperatorKind opcode, 165 Expr *op); 166 167 ExprResult complete(Expr *syntacticForm); 168 169 OpaqueValueExpr *capture(Expr *op); 170 OpaqueValueExpr *captureValueAsResult(Expr *op); 171 172 void setResultToLastSemantic() { 173 assert(ResultIndex == PseudoObjectExpr::NoResult); 174 ResultIndex = Semantics.size() - 1; 175 } 176 177 /// Return true if assignments have a non-void result. 178 virtual bool assignmentsHaveResult() { return true; } 179 180 virtual Expr *rebuildAndCaptureObject(Expr *) = 0; 181 virtual ExprResult buildGet() = 0; 182 virtual ExprResult buildSet(Expr *, SourceLocation, 183 bool captureSetValueAsResult) = 0; 184 }; 185 186 /// A PseudoOpBuilder for Objective-C @properties. 187 class ObjCPropertyOpBuilder : public PseudoOpBuilder { 188 ObjCPropertyRefExpr *RefExpr; 189 OpaqueValueExpr *InstanceReceiver; 190 ObjCMethodDecl *Getter; 191 192 ObjCMethodDecl *Setter; 193 Selector SetterSelector; 194 195 public: 196 ObjCPropertyOpBuilder(Sema &S, ObjCPropertyRefExpr *refExpr) : 197 PseudoOpBuilder(S, refExpr->getLocation()), RefExpr(refExpr), 198 InstanceReceiver(0), Getter(0), Setter(0) { 199 } 200 201 ExprResult buildRValueOperation(Expr *op); 202 ExprResult buildAssignmentOperation(Scope *Sc, 203 SourceLocation opLoc, 204 BinaryOperatorKind opcode, 205 Expr *LHS, Expr *RHS); 206 ExprResult buildIncDecOperation(Scope *Sc, SourceLocation opLoc, 207 UnaryOperatorKind opcode, 208 Expr *op); 209 210 bool tryBuildGetOfReference(Expr *op, ExprResult &result); 211 bool findSetter(); 212 bool findGetter(); 213 214 Expr *rebuildAndCaptureObject(Expr *syntacticBase); 215 ExprResult buildGet(); 216 ExprResult buildSet(Expr *op, SourceLocation, bool); 217 }; 218} 219 220/// Capture the given expression in an OpaqueValueExpr. 221OpaqueValueExpr *PseudoOpBuilder::capture(Expr *e) { 222 // Make a new OVE whose source is the given expression. 223 OpaqueValueExpr *captured = 224 new (S.Context) OpaqueValueExpr(GenericLoc, e->getType(), 225 e->getValueKind()); 226 captured->setSourceExpr(e); 227 228 // Make sure we bind that in the semantics. 229 addSemanticExpr(captured); 230 return captured; 231} 232 233/// Capture the given expression as the result of this pseudo-object 234/// operation. This routine is safe against expressions which may 235/// already be captured. 236/// 237/// \param Returns the captured expression, which will be the 238/// same as the input if the input was already captured 239OpaqueValueExpr *PseudoOpBuilder::captureValueAsResult(Expr *e) { 240 assert(ResultIndex == PseudoObjectExpr::NoResult); 241 242 // If the expression hasn't already been captured, just capture it 243 // and set the new semantic 244 if (!isa<OpaqueValueExpr>(e)) { 245 OpaqueValueExpr *cap = capture(e); 246 setResultToLastSemantic(); 247 return cap; 248 } 249 250 // Otherwise, it must already be one of our semantic expressions; 251 // set ResultIndex to its index. 252 unsigned index = 0; 253 for (;; ++index) { 254 assert(index < Semantics.size() && 255 "captured expression not found in semantics!"); 256 if (e == Semantics[index]) break; 257 } 258 ResultIndex = index; 259 return cast<OpaqueValueExpr>(e); 260} 261 262/// The routine which creates the final PseudoObjectExpr. 263ExprResult PseudoOpBuilder::complete(Expr *syntactic) { 264 return PseudoObjectExpr::Create(S.Context, syntactic, 265 Semantics, ResultIndex); 266} 267 268/// The main skeleton for building an r-value operation. 269ExprResult PseudoOpBuilder::buildRValueOperation(Expr *op) { 270 Expr *syntacticBase = rebuildAndCaptureObject(op); 271 272 ExprResult getExpr = buildGet(); 273 if (getExpr.isInvalid()) return ExprError(); 274 addResultSemanticExpr(getExpr.take()); 275 276 return complete(syntacticBase); 277} 278 279/// The basic skeleton for building a simple or compound 280/// assignment operation. 281ExprResult 282PseudoOpBuilder::buildAssignmentOperation(Scope *Sc, SourceLocation opcLoc, 283 BinaryOperatorKind opcode, 284 Expr *LHS, Expr *RHS) { 285 assert(BinaryOperator::isAssignmentOp(opcode)); 286 287 Expr *syntacticLHS = rebuildAndCaptureObject(LHS); 288 OpaqueValueExpr *capturedRHS = capture(RHS); 289 290 Expr *syntactic; 291 292 ExprResult result; 293 if (opcode == BO_Assign) { 294 result = capturedRHS; 295 syntactic = new (S.Context) BinaryOperator(syntacticLHS, capturedRHS, 296 opcode, capturedRHS->getType(), 297 capturedRHS->getValueKind(), 298 OK_Ordinary, opcLoc); 299 } else { 300 ExprResult opLHS = buildGet(); 301 if (opLHS.isInvalid()) return ExprError(); 302 303 // Build an ordinary, non-compound operation. 304 BinaryOperatorKind nonCompound = 305 BinaryOperator::getOpForCompoundAssignment(opcode); 306 result = S.BuildBinOp(Sc, opcLoc, nonCompound, 307 opLHS.take(), capturedRHS); 308 if (result.isInvalid()) return ExprError(); 309 310 syntactic = 311 new (S.Context) CompoundAssignOperator(syntacticLHS, capturedRHS, opcode, 312 result.get()->getType(), 313 result.get()->getValueKind(), 314 OK_Ordinary, 315 opLHS.get()->getType(), 316 result.get()->getType(), 317 opcLoc); 318 } 319 320 // The result of the assignment, if not void, is the value set into 321 // the l-value. 322 result = buildSet(result.take(), opcLoc, assignmentsHaveResult()); 323 if (result.isInvalid()) return ExprError(); 324 addSemanticExpr(result.take()); 325 326 return complete(syntactic); 327} 328 329/// The basic skeleton for building an increment or decrement 330/// operation. 331ExprResult 332PseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc, 333 UnaryOperatorKind opcode, 334 Expr *op) { 335 assert(UnaryOperator::isIncrementDecrementOp(opcode)); 336 337 Expr *syntacticOp = rebuildAndCaptureObject(op); 338 339 // Load the value. 340 ExprResult result = buildGet(); 341 if (result.isInvalid()) return ExprError(); 342 343 QualType resultType = result.get()->getType(); 344 345 // That's the postfix result. 346 if (UnaryOperator::isPostfix(opcode) && assignmentsHaveResult()) { 347 result = capture(result.take()); 348 setResultToLastSemantic(); 349 } 350 351 // Add or subtract a literal 1. 352 llvm::APInt oneV(S.Context.getTypeSize(S.Context.IntTy), 1); 353 Expr *one = IntegerLiteral::Create(S.Context, oneV, S.Context.IntTy, 354 GenericLoc); 355 356 if (UnaryOperator::isIncrementOp(opcode)) { 357 result = S.BuildBinOp(Sc, opcLoc, BO_Add, result.take(), one); 358 } else { 359 result = S.BuildBinOp(Sc, opcLoc, BO_Sub, result.take(), one); 360 } 361 if (result.isInvalid()) return ExprError(); 362 363 // Store that back into the result. The value stored is the result 364 // of a prefix operation. 365 result = buildSet(result.take(), opcLoc, 366 UnaryOperator::isPrefix(opcode) && assignmentsHaveResult()); 367 if (result.isInvalid()) return ExprError(); 368 addSemanticExpr(result.take()); 369 370 UnaryOperator *syntactic = 371 new (S.Context) UnaryOperator(syntacticOp, opcode, resultType, 372 VK_LValue, OK_Ordinary, opcLoc); 373 return complete(syntactic); 374} 375 376 377//===----------------------------------------------------------------------===// 378// Objective-C @property and implicit property references 379//===----------------------------------------------------------------------===// 380 381/// Look up a method in the receiver type of an Objective-C property 382/// reference. 383static ObjCMethodDecl *LookupMethodInReceiverType(Sema &S, Selector sel, 384 const ObjCPropertyRefExpr *PRE) { 385 if (PRE->isObjectReceiver()) { 386 const ObjCObjectPointerType *PT = 387 PRE->getBase()->getType()->castAs<ObjCObjectPointerType>(); 388 389 // Special case for 'self' in class method implementations. 390 if (PT->isObjCClassType() && 391 S.isSelfExpr(const_cast<Expr*>(PRE->getBase()))) { 392 // This cast is safe because isSelfExpr is only true within 393 // methods. 394 ObjCMethodDecl *method = 395 cast<ObjCMethodDecl>(S.CurContext->getNonClosureAncestor()); 396 return S.LookupMethodInObjectType(sel, 397 S.Context.getObjCInterfaceType(method->getClassInterface()), 398 /*instance*/ false); 399 } 400 401 return S.LookupMethodInObjectType(sel, PT->getPointeeType(), true); 402 } 403 404 if (PRE->isSuperReceiver()) { 405 if (const ObjCObjectPointerType *PT = 406 PRE->getSuperReceiverType()->getAs<ObjCObjectPointerType>()) 407 return S.LookupMethodInObjectType(sel, PT->getPointeeType(), true); 408 409 return S.LookupMethodInObjectType(sel, PRE->getSuperReceiverType(), false); 410 } 411 412 assert(PRE->isClassReceiver() && "Invalid expression"); 413 QualType IT = S.Context.getObjCInterfaceType(PRE->getClassReceiver()); 414 return S.LookupMethodInObjectType(sel, IT, false); 415} 416 417bool ObjCPropertyOpBuilder::findGetter() { 418 if (Getter) return true; 419 420 Getter = LookupMethodInReceiverType(S, RefExpr->getGetterSelector(), RefExpr); 421 return (Getter != 0); 422} 423 424/// Try to find the most accurate setter declaration for the property 425/// reference. 426/// 427/// \return true if a setter was found, in which case Setter 428bool ObjCPropertyOpBuilder::findSetter() { 429 // For implicit properties, just trust the lookup we already did. 430 if (RefExpr->isImplicitProperty()) { 431 if (ObjCMethodDecl *setter = RefExpr->getImplicitPropertySetter()) { 432 Setter = setter; 433 SetterSelector = setter->getSelector(); 434 return true; 435 } else { 436 IdentifierInfo *getterName = 437 RefExpr->getImplicitPropertyGetter()->getSelector() 438 .getIdentifierInfoForSlot(0); 439 SetterSelector = 440 SelectorTable::constructSetterName(S.PP.getIdentifierTable(), 441 S.PP.getSelectorTable(), 442 getterName); 443 return false; 444 } 445 } 446 447 // For explicit properties, this is more involved. 448 ObjCPropertyDecl *prop = RefExpr->getExplicitProperty(); 449 SetterSelector = prop->getSetterName(); 450 451 // Do a normal method lookup first. 452 if (ObjCMethodDecl *setter = 453 LookupMethodInReceiverType(S, SetterSelector, RefExpr)) { 454 Setter = setter; 455 return true; 456 } 457 458 // That can fail in the somewhat crazy situation that we're 459 // type-checking a message send within the @interface declaration 460 // that declared the @property. But it's not clear that that's 461 // valuable to support. 462 463 return false; 464} 465 466/// Capture the base object of an Objective-C property expression. 467Expr *ObjCPropertyOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) { 468 assert(InstanceReceiver == 0); 469 470 // If we have a base, capture it in an OVE and rebuild the syntactic 471 // form to use the OVE as its base. 472 if (RefExpr->isObjectReceiver()) { 473 InstanceReceiver = capture(RefExpr->getBase()); 474 475 syntacticBase = 476 ObjCPropertyRefRebuilder(S, InstanceReceiver).rebuild(syntacticBase); 477 } 478 479 return syntacticBase; 480} 481 482/// Load from an Objective-C property reference. 483ExprResult ObjCPropertyOpBuilder::buildGet() { 484 findGetter(); 485 assert(Getter); 486 487 QualType receiverType; 488 SourceLocation superLoc; 489 if (RefExpr->isClassReceiver()) { 490 receiverType = S.Context.getObjCInterfaceType(RefExpr->getClassReceiver()); 491 } else if (RefExpr->isSuperReceiver()) { 492 superLoc = RefExpr->getReceiverLocation(); 493 receiverType = RefExpr->getSuperReceiverType(); 494 } else { 495 assert(InstanceReceiver); 496 receiverType = InstanceReceiver->getType(); 497 } 498 499 // Build a message-send. 500 ExprResult msg; 501 if (Getter->isInstanceMethod() || RefExpr->isObjectReceiver()) { 502 assert(InstanceReceiver || RefExpr->isSuperReceiver()); 503 msg = S.BuildInstanceMessage(InstanceReceiver, receiverType, superLoc, 504 Getter->getSelector(), Getter, 505 GenericLoc, GenericLoc, GenericLoc, 506 MultiExprArg()); 507 } else { 508 TypeSourceInfo *receiverTypeInfo = 0; 509 if (!RefExpr->isSuperReceiver()) 510 receiverTypeInfo = S.Context.getTrivialTypeSourceInfo(receiverType); 511 512 msg = S.BuildClassMessage(receiverTypeInfo, receiverType, superLoc, 513 Getter->getSelector(), Getter, 514 GenericLoc, GenericLoc, GenericLoc, 515 MultiExprArg()); 516 } 517 return msg; 518} 519 520/// Store to an Objective-C property reference. 521/// 522/// \param bindSetValueAsResult - If true, capture the actual 523/// value being set as the value of the property operation. 524ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc, 525 bool captureSetValueAsResult) { 526 bool hasSetter = findSetter(); 527 assert(hasSetter); (void) hasSetter; 528 529 QualType receiverType; 530 SourceLocation superLoc; 531 if (RefExpr->isClassReceiver()) { 532 receiverType = S.Context.getObjCInterfaceType(RefExpr->getClassReceiver()); 533 } else if (RefExpr->isSuperReceiver()) { 534 superLoc = RefExpr->getReceiverLocation(); 535 receiverType = RefExpr->getSuperReceiverType(); 536 } else { 537 assert(InstanceReceiver); 538 receiverType = InstanceReceiver->getType(); 539 } 540 541 // Use assignment constraints when possible; they give us better 542 // diagnostics. "When possible" basically means anything except a 543 // C++ class type. 544 if (!S.getLangOptions().CPlusPlus || !op->getType()->isRecordType()) { 545 QualType paramType = (*Setter->param_begin())->getType(); 546 if (!S.getLangOptions().CPlusPlus || !paramType->isRecordType()) { 547 ExprResult opResult = op; 548 Sema::AssignConvertType assignResult 549 = S.CheckSingleAssignmentConstraints(paramType, opResult); 550 if (S.DiagnoseAssignmentResult(assignResult, opcLoc, paramType, 551 op->getType(), opResult.get(), 552 Sema::AA_Assigning)) 553 return ExprError(); 554 555 op = opResult.take(); 556 assert(op && "successful assignment left argument invalid?"); 557 } 558 } 559 560 // Arguments. 561 Expr *args[] = { op }; 562 563 // Build a message-send. 564 ExprResult msg; 565 if (Setter->isInstanceMethod() || RefExpr->isObjectReceiver()) { 566 msg = S.BuildInstanceMessage(InstanceReceiver, receiverType, superLoc, 567 SetterSelector, Setter, 568 GenericLoc, GenericLoc, GenericLoc, 569 MultiExprArg(args, 1)); 570 } else { 571 TypeSourceInfo *receiverTypeInfo = 0; 572 if (!RefExpr->isSuperReceiver()) 573 receiverTypeInfo = S.Context.getTrivialTypeSourceInfo(receiverType); 574 575 msg = S.BuildClassMessage(receiverTypeInfo, receiverType, superLoc, 576 SetterSelector, Setter, 577 GenericLoc, GenericLoc, GenericLoc, 578 MultiExprArg(args, 1)); 579 } 580 581 if (!msg.isInvalid() && captureSetValueAsResult) { 582 ObjCMessageExpr *msgExpr = 583 cast<ObjCMessageExpr>(msg.get()->IgnoreImplicit()); 584 Expr *arg = msgExpr->getArg(0); 585 msgExpr->setArg(0, captureValueAsResult(arg)); 586 } 587 588 return msg; 589} 590 591/// @property-specific behavior for doing lvalue-to-rvalue conversion. 592ExprResult ObjCPropertyOpBuilder::buildRValueOperation(Expr *op) { 593 // Explicit properties always have getters, but implicit ones don't. 594 // Check that before proceeding. 595 if (RefExpr->isImplicitProperty() && 596 !RefExpr->getImplicitPropertyGetter()) { 597 S.Diag(RefExpr->getLocation(), diag::err_getter_not_found) 598 << RefExpr->getBase()->getType(); 599 return ExprError(); 600 } 601 602 ExprResult result = PseudoOpBuilder::buildRValueOperation(op); 603 if (result.isInvalid()) return ExprError(); 604 605 if (RefExpr->isExplicitProperty() && !Getter->hasRelatedResultType()) 606 S.DiagnosePropertyAccessorMismatch(RefExpr->getExplicitProperty(), 607 Getter, RefExpr->getLocation()); 608 609 // As a special case, if the method returns 'id', try to get 610 // a better type from the property. 611 if (RefExpr->isExplicitProperty() && result.get()->isRValue() && 612 result.get()->getType()->isObjCIdType()) { 613 QualType propType = RefExpr->getExplicitProperty()->getType(); 614 if (const ObjCObjectPointerType *ptr 615 = propType->getAs<ObjCObjectPointerType>()) { 616 if (!ptr->isObjCIdType()) 617 result = S.ImpCastExprToType(result.get(), propType, CK_BitCast); 618 } 619 } 620 621 return result; 622} 623 624/// Try to build this as a call to a getter that returns a reference. 625/// 626/// \return true if it was possible, whether or not it actually 627/// succeeded 628bool ObjCPropertyOpBuilder::tryBuildGetOfReference(Expr *op, 629 ExprResult &result) { 630 if (!S.getLangOptions().CPlusPlus) return false; 631 632 findGetter(); 633 assert(Getter && "property has no setter and no getter!"); 634 635 // Only do this if the getter returns an l-value reference type. 636 QualType resultType = Getter->getResultType(); 637 if (!resultType->isLValueReferenceType()) return false; 638 639 result = buildRValueOperation(op); 640 return true; 641} 642 643/// @property-specific behavior for doing assignments. 644ExprResult 645ObjCPropertyOpBuilder::buildAssignmentOperation(Scope *Sc, 646 SourceLocation opcLoc, 647 BinaryOperatorKind opcode, 648 Expr *LHS, Expr *RHS) { 649 assert(BinaryOperator::isAssignmentOp(opcode)); 650 651 // If there's no setter, we have no choice but to try to assign to 652 // the result of the getter. 653 if (!findSetter()) { 654 ExprResult result; 655 if (tryBuildGetOfReference(LHS, result)) { 656 if (result.isInvalid()) return ExprError(); 657 return S.BuildBinOp(Sc, opcLoc, opcode, result.take(), RHS); 658 } 659 660 // Otherwise, it's an error. 661 S.Diag(opcLoc, diag::err_nosetter_property_assignment) 662 << unsigned(RefExpr->isImplicitProperty()) 663 << SetterSelector 664 << LHS->getSourceRange() << RHS->getSourceRange(); 665 return ExprError(); 666 } 667 668 // If there is a setter, we definitely want to use it. 669 670 // Verify that we can do a compound assignment. 671 if (opcode != BO_Assign && !findGetter()) { 672 S.Diag(opcLoc, diag::err_nogetter_property_compound_assignment) 673 << LHS->getSourceRange() << RHS->getSourceRange(); 674 return ExprError(); 675 } 676 677 ExprResult result = 678 PseudoOpBuilder::buildAssignmentOperation(Sc, opcLoc, opcode, LHS, RHS); 679 if (result.isInvalid()) return ExprError(); 680 681 // Various warnings about property assignments in ARC. 682 if (S.getLangOptions().ObjCAutoRefCount && InstanceReceiver) { 683 S.checkRetainCycles(InstanceReceiver->getSourceExpr(), RHS); 684 S.checkUnsafeExprAssigns(opcLoc, LHS, RHS); 685 } 686 687 return result; 688} 689 690/// @property-specific behavior for doing increments and decrements. 691ExprResult 692ObjCPropertyOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc, 693 UnaryOperatorKind opcode, 694 Expr *op) { 695 // If there's no setter, we have no choice but to try to assign to 696 // the result of the getter. 697 if (!findSetter()) { 698 ExprResult result; 699 if (tryBuildGetOfReference(op, result)) { 700 if (result.isInvalid()) return ExprError(); 701 return S.BuildUnaryOp(Sc, opcLoc, opcode, result.take()); 702 } 703 704 // Otherwise, it's an error. 705 S.Diag(opcLoc, diag::err_nosetter_property_incdec) 706 << unsigned(RefExpr->isImplicitProperty()) 707 << unsigned(UnaryOperator::isDecrementOp(opcode)) 708 << SetterSelector 709 << op->getSourceRange(); 710 return ExprError(); 711 } 712 713 // If there is a setter, we definitely want to use it. 714 715 // We also need a getter. 716 if (!findGetter()) { 717 assert(RefExpr->isImplicitProperty()); 718 S.Diag(opcLoc, diag::err_nogetter_property_incdec) 719 << unsigned(UnaryOperator::isDecrementOp(opcode)) 720 << RefExpr->getImplicitPropertyGetter()->getSelector() // FIXME! 721 << op->getSourceRange(); 722 return ExprError(); 723 } 724 725 return PseudoOpBuilder::buildIncDecOperation(Sc, opcLoc, opcode, op); 726} 727 728//===----------------------------------------------------------------------===// 729// General Sema routines. 730//===----------------------------------------------------------------------===// 731 732ExprResult Sema::checkPseudoObjectRValue(Expr *E) { 733 Expr *opaqueRef = E->IgnoreParens(); 734 if (ObjCPropertyRefExpr *refExpr 735 = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) { 736 ObjCPropertyOpBuilder builder(*this, refExpr); 737 return builder.buildRValueOperation(E); 738 } else { 739 llvm_unreachable("unknown pseudo-object kind!"); 740 } 741} 742 743/// Check an increment or decrement of a pseudo-object expression. 744ExprResult Sema::checkPseudoObjectIncDec(Scope *Sc, SourceLocation opcLoc, 745 UnaryOperatorKind opcode, Expr *op) { 746 // Do nothing if the operand is dependent. 747 if (op->isTypeDependent()) 748 return new (Context) UnaryOperator(op, opcode, Context.DependentTy, 749 VK_RValue, OK_Ordinary, opcLoc); 750 751 assert(UnaryOperator::isIncrementDecrementOp(opcode)); 752 Expr *opaqueRef = op->IgnoreParens(); 753 if (ObjCPropertyRefExpr *refExpr 754 = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) { 755 ObjCPropertyOpBuilder builder(*this, refExpr); 756 return builder.buildIncDecOperation(Sc, opcLoc, opcode, op); 757 } else { 758 llvm_unreachable("unknown pseudo-object kind!"); 759 } 760} 761 762ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc, 763 BinaryOperatorKind opcode, 764 Expr *LHS, Expr *RHS) { 765 // Do nothing if either argument is dependent. 766 if (LHS->isTypeDependent() || RHS->isTypeDependent()) 767 return new (Context) BinaryOperator(LHS, RHS, opcode, Context.DependentTy, 768 VK_RValue, OK_Ordinary, opcLoc); 769 770 // Filter out non-overload placeholder types in the RHS. 771 if (const BuiltinType *PTy = RHS->getType()->getAsPlaceholderType()) { 772 if (PTy->getKind() != BuiltinType::Overload) { 773 ExprResult result = CheckPlaceholderExpr(RHS); 774 if (result.isInvalid()) return ExprError(); 775 RHS = result.take(); 776 } 777 } 778 779 Expr *opaqueRef = LHS->IgnoreParens(); 780 if (ObjCPropertyRefExpr *refExpr 781 = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) { 782 ObjCPropertyOpBuilder builder(*this, refExpr); 783 return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS); 784 } else { 785 llvm_unreachable("unknown pseudo-object kind!"); 786 } 787} 788