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