Restore r142914 and r142915, now with missing file and apparent
GCC compiler workaround.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142931 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp
new file mode 100644
index 0000000..92171c5
--- /dev/null
+++ b/lib/Sema/SemaPseudoObject.cpp
@@ -0,0 +1,342 @@
+//===--- SemaPseudoObject.cpp - Semantic Analysis for Pseudo-Objects ------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file implements semantic analysis for expressions involving
+//  pseudo-object references.  Pseudo-objects are conceptual objects
+//  whose storage is entirely abstract and all accesses to which are
+//  translated through some sort of abstraction barrier.
+//
+//  For example, Objective-C objects can have "properties", either
+//  declared or undeclared.  A property may be accessed by writing
+//    expr.prop
+//  where 'expr' is an r-value of Objective-C pointer type and 'prop'
+//  is the name of the property.  If this expression is used in a context
+//  needing an r-value, it is treated as if it were a message-send
+//  of the associated 'getter' selector, typically:
+//    [expr prop]
+//  If it is used as the LHS of a simple assignment, it is treated
+//  as a message-send of the associated 'setter' selector, typically:
+//    [expr setProp: RHS]
+//  If it is used as the LHS of a compound assignment, or the operand
+//  of a unary increment or decrement, both are required;  for example,
+//  'expr.prop *= 100' would be translated to:
+//    [expr setProp: [expr prop] * 100]
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang;
+using namespace sema;
+
+static ObjCMethodDecl *LookupMethodInReceiverType(Sema &S, Selector sel,
+                                            const ObjCPropertyRefExpr *PRE) {
+  bool instanceProperty;
+  QualType searchType;
+  if (PRE->isObjectReceiver()) {
+    searchType = PRE->getBase()->getType()
+      ->castAs<ObjCObjectPointerType>()->getPointeeType();
+    instanceProperty = true;
+  } else if (PRE->isSuperReceiver()) {
+    searchType = PRE->getSuperReceiverType();
+    instanceProperty = false;
+    if (const ObjCObjectPointerType *PT
+        = searchType->getAs<ObjCObjectPointerType>()) {
+      searchType = PT->getPointeeType();
+      instanceProperty = true;
+    }
+  } else if (PRE->isClassReceiver()) {
+    searchType = S.Context.getObjCInterfaceType(PRE->getClassReceiver());
+    instanceProperty = false;
+  }
+
+  return S.LookupMethodInObjectType(sel, searchType, instanceProperty);
+}
+
+ExprResult Sema::checkPseudoObjectRValue(Expr *E) {
+  assert(E->getValueKind() == VK_LValue &&
+         E->getObjectKind() == OK_ObjCProperty);
+  const ObjCPropertyRefExpr *PRE = E->getObjCProperty();
+
+  QualType ReceiverType;
+  if (PRE->isObjectReceiver())
+    ReceiverType = PRE->getBase()->getType();
+  else if (PRE->isSuperReceiver())
+    ReceiverType = PRE->getSuperReceiverType();
+  else
+    ReceiverType = Context.getObjCInterfaceType(PRE->getClassReceiver());
+    
+  ExprValueKind VK = VK_RValue;
+  QualType T;
+  if (PRE->isImplicitProperty()) {
+    if (ObjCMethodDecl *GetterMethod = 
+          PRE->getImplicitPropertyGetter()) {
+      T = getMessageSendResultType(ReceiverType, GetterMethod,
+                                   PRE->isClassReceiver(), 
+                                   PRE->isSuperReceiver());
+      VK = Expr::getValueKindForType(GetterMethod->getResultType());
+    } else {
+      Diag(PRE->getLocation(), diag::err_getter_not_found)
+            << PRE->getBase()->getType();
+      return ExprError();
+    }
+  } else {
+    ObjCPropertyDecl *prop = PRE->getExplicitProperty();
+
+    ObjCMethodDecl *getter =
+      LookupMethodInReceiverType(*this, prop->getGetterName(), PRE);
+    if (getter && !getter->hasRelatedResultType())
+      DiagnosePropertyAccessorMismatch(prop, getter, PRE->getLocation());
+    if (!getter) getter = prop->getGetterMethodDecl();
+
+    // Figure out the type of the expression.  Mostly this is the
+    // result type of the getter, if possible.
+    if (getter) {
+      T = getMessageSendResultType(ReceiverType, getter, 
+                                   PRE->isClassReceiver(), 
+                                   PRE->isSuperReceiver());
+      VK = Expr::getValueKindForType(getter->getResultType());
+
+      // As a special case, if the method returns 'id', try to get a
+      // better type from the property.
+      if (VK == VK_RValue && T->isObjCIdType() &&
+          prop->getType()->isObjCRetainableType())
+        T = prop->getType();
+    } else {
+      T = prop->getType();
+      VK = Expr::getValueKindForType(T);
+      T = T.getNonLValueExprType(Context);
+    }
+  }
+
+  E->setType(T);
+  E = ImplicitCastExpr::Create(Context, T, CK_GetObjCProperty, E, 0, VK);
+  
+  ExprResult Result = MaybeBindToTemporary(E);
+  if (!Result.isInvalid())
+    E = Result.take();
+
+  return Owned(E);
+}
+
+namespace {
+  struct PseudoObjectInfo {
+    const ObjCPropertyRefExpr *RefExpr;
+    bool HasSetter;
+    Selector SetterSelector;
+    ParmVarDecl *SetterParam;
+    QualType SetterParamType;
+
+    void setSetter(ObjCMethodDecl *setter) {
+      HasSetter = true;
+      SetterParam = *setter->param_begin();
+      SetterParamType = SetterParam->getType().getUnqualifiedType();
+    }
+
+    PseudoObjectInfo(Sema &S, Expr *E)
+      : RefExpr(E->getObjCProperty()), HasSetter(false), SetterParam(0) {
+
+      assert(E->getValueKind() == VK_LValue &&
+             E->getObjectKind() == OK_ObjCProperty);
+
+      // Try to find a setter.
+
+      // For implicit properties, just trust the lookup we already did.
+      if (RefExpr->isImplicitProperty()) {
+        if (ObjCMethodDecl *setter = RefExpr->getImplicitPropertySetter()) {
+          setSetter(setter);
+          SetterSelector = setter->getSelector();
+        } else {
+          IdentifierInfo *getterName =
+            RefExpr->getImplicitPropertyGetter()->getSelector()
+              .getIdentifierInfoForSlot(0);
+          SetterSelector = 
+            SelectorTable::constructSetterName(S.PP.getIdentifierTable(),
+                                               S.PP.getSelectorTable(),
+                                               getterName);
+        }
+        return;
+      }
+
+      // For explicit properties, this is more involved.
+      ObjCPropertyDecl *prop = RefExpr->getExplicitProperty();
+      SetterSelector = prop->getSetterName();
+
+      // Do a normal method lookup first.
+      if (ObjCMethodDecl *setter =
+            LookupMethodInReceiverType(S, SetterSelector, RefExpr)) {
+        setSetter(setter);
+        return;
+      }
+
+      // If that failed, trust the type on the @property declaration.
+      if (!prop->isReadOnly()) {
+        HasSetter = true;
+        SetterParamType = prop->getType().getUnqualifiedType();
+      }
+    }
+  };
+}
+
+/// Check an increment or decrement of a pseudo-object expression.
+ExprResult Sema::checkPseudoObjectIncDec(Scope *S, SourceLocation opcLoc,
+                                         UnaryOperatorKind opcode, Expr *op) {
+  assert(UnaryOperator::isIncrementDecrementOp(opcode));
+  PseudoObjectInfo info(*this, op);
+
+  // If there's no setter, we have no choice but to try to assign to
+  // the result of the getter.
+  if (!info.HasSetter) {
+    QualType resultType = info.RefExpr->getGetterResultType();
+    assert(!resultType.isNull() && "property has no setter and no getter!");
+
+    // Only do this if the getter returns an l-value reference type.
+    if (const LValueReferenceType *refType
+          = resultType->getAs<LValueReferenceType>()) {
+      op = ImplicitCastExpr::Create(Context, refType->getPointeeType(),
+                                    CK_GetObjCProperty, op, 0, VK_LValue);
+      return BuildUnaryOp(S, opcLoc, opcode, op);
+    }
+
+    // Otherwise, it's an error.
+    Diag(opcLoc, diag::err_nosetter_property_incdec)
+      << unsigned(info.RefExpr->isImplicitProperty())
+      << unsigned(UnaryOperator::isDecrementOp(opcode))
+      << info.SetterSelector
+      << op->getSourceRange();
+    return ExprError();
+  }
+
+  // ++/-- behave like compound assignments, i.e. they need a getter.
+  QualType getterResultType = info.RefExpr->getGetterResultType();
+  if (getterResultType.isNull()) {
+    assert(info.RefExpr->isImplicitProperty());
+    Diag(opcLoc, diag::err_nogetter_property_incdec)
+      << unsigned(UnaryOperator::isDecrementOp(opcode))
+      << info.RefExpr->getImplicitPropertyGetter()->getSelector()
+      << op->getSourceRange();
+    return ExprError();
+  }
+
+  // HACK: change the type of the operand to prevent further placeholder
+  // transformation.
+  op->setType(getterResultType.getNonLValueExprType(Context));
+  op->setObjectKind(OK_Ordinary);
+  
+  ExprResult result = CreateBuiltinUnaryOp(opcLoc, opcode, op);
+  if (result.isInvalid()) return ExprError();
+
+  // Change the object kind back.
+  op->setObjectKind(OK_ObjCProperty);
+  return result;
+}
+
+ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc,
+                                             BinaryOperatorKind opcode,
+                                             Expr *LHS, Expr *RHS) {
+  assert(BinaryOperator::isAssignmentOp(opcode));
+  PseudoObjectInfo info(*this, LHS);
+
+  // If there's no setter, we have no choice but to try to assign to
+  // the result of the getter.
+  if (!info.HasSetter) {
+    QualType resultType = info.RefExpr->getGetterResultType();
+    assert(!resultType.isNull() && "property has no setter and no getter!");
+
+    // Only do this if the getter returns an l-value reference type.
+    if (const LValueReferenceType *refType
+          = resultType->getAs<LValueReferenceType>()) {
+      LHS = ImplicitCastExpr::Create(Context, refType->getPointeeType(),
+                                     CK_GetObjCProperty, LHS, 0, VK_LValue);
+      return BuildBinOp(S, opcLoc, opcode, LHS, RHS);
+    }
+
+    // Otherwise, it's an error.
+    Diag(opcLoc, diag::err_nosetter_property_assignment)
+      << unsigned(info.RefExpr->isImplicitProperty())
+      << info.SetterSelector
+      << LHS->getSourceRange() << RHS->getSourceRange();
+    return ExprError();
+  }
+
+  // If there is a setter, we definitely want to use it.
+
+  // If this is a simple assignment, just initialize the parameter
+  // with the RHS.
+  if (opcode == BO_Assign) {
+    LHS->setType(info.SetterParamType.getNonLValueExprType(Context));
+
+    // Under certain circumstances, we need to type-check the RHS as a
+    // straight-up parameter initialization.  This gives somewhat
+    // inferior diagnostics, so we try to avoid it.
+
+    if (RHS->isTypeDependent()) {
+      // Just build the expression.
+
+    } else if ((getLangOptions().CPlusPlus && LHS->getType()->isRecordType()) ||
+               (getLangOptions().ObjCAutoRefCount &&
+                info.SetterParam &&
+                info.SetterParam->hasAttr<NSConsumedAttr>())) {
+      InitializedEntity param = (info.SetterParam
+        ? InitializedEntity::InitializeParameter(Context, info.SetterParam)
+        : InitializedEntity::InitializeParameter(Context, info.SetterParamType,
+                                                 /*consumed*/ false));
+      ExprResult arg = PerformCopyInitialization(param, opcLoc, RHS);
+      if (arg.isInvalid()) return ExprError();
+      RHS = arg.take();
+
+      // Warn about assignments of +1 objects to unsafe pointers in ARC.
+      // CheckAssignmentOperands does this on the other path.
+      if (getLangOptions().ObjCAutoRefCount)
+        checkUnsafeExprAssigns(opcLoc, LHS, RHS);
+    } else {
+      ExprResult RHSResult = Owned(RHS);
+
+      LHS->setObjectKind(OK_Ordinary);
+      QualType resultType = CheckAssignmentOperands(LHS, RHSResult, opcLoc,
+                                                    /*compound*/ QualType());
+      LHS->setObjectKind(OK_ObjCProperty);
+
+      if (!RHSResult.isInvalid()) RHS = RHSResult.take();
+      if (resultType.isNull()) return ExprError();
+    }
+
+    // Warn about property sets in ARC that might cause retain cycles.
+    if (getLangOptions().ObjCAutoRefCount && !info.RefExpr->isSuperReceiver())
+      checkRetainCycles(const_cast<Expr*>(info.RefExpr->getBase()), RHS);
+
+    return new (Context) BinaryOperator(LHS, RHS, opcode, RHS->getType(),
+                                        RHS->getValueKind(),
+                                        RHS->getObjectKind(),
+                                        opcLoc);
+  }
+
+  // If this is a compound assignment, we need to use the getter, too.
+  QualType getterResultType = info.RefExpr->getGetterResultType();
+  if (getterResultType.isNull()) {
+    Diag(opcLoc, diag::err_nogetter_property_compound_assignment)
+      << LHS->getSourceRange() << RHS->getSourceRange();
+    return ExprError();
+  }
+
+  // HACK: change the type of the LHS to prevent further placeholder
+  // transformation.
+  LHS->setType(getterResultType.getNonLValueExprType(Context));
+  LHS->setObjectKind(OK_Ordinary);
+  
+  ExprResult result = CreateBuiltinBinOp(opcLoc, opcode, LHS, RHS);
+  if (result.isInvalid()) return ExprError();
+
+  // Change the object kind back.
+  LHS->setObjectKind(OK_ObjCProperty);
+  return result;
+}