Automatic Reference Counting.

Language-design credit goes to a lot of people, but I particularly want
to single out Blaine Garst and Patrick Beard for their contributions.

Compiler implementation credit goes to Argyrios, Doug, Fariborz, and myself,
in no particular order.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133103 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp
index 619a5b9..fda4e0c 100644
--- a/lib/Sema/AttributeList.cpp
+++ b/lib/Sema/AttributeList.cpp
@@ -177,6 +177,11 @@
     .Case("cf_consumed", AT_cf_consumed)
     .Case("cf_returns_not_retained", AT_cf_returns_not_retained)
     .Case("cf_returns_retained", AT_cf_returns_retained)
+    .Case("cf_returns_autoreleased", AT_cf_returns_autoreleased)
+    .Case("ns_consumes_self", AT_ns_consumes_self)
+    .Case("ns_consumed", AT_ns_consumed)
+    .Case("objc_lifetime", AT_objc_lifetime)
+    .Case("objc_precise_lifetime", AT_objc_precise_lifetime)
     .Case("ownership_returns", AT_ownership_returns)
     .Case("ownership_holds", AT_ownership_holds)
     .Case("ownership_takes", AT_ownership_takes)
diff --git a/lib/Sema/DelayedDiagnostic.cpp b/lib/Sema/DelayedDiagnostic.cpp
index af548fe..c6744ed 100644
--- a/lib/Sema/DelayedDiagnostic.cpp
+++ b/lib/Sema/DelayedDiagnostic.cpp
@@ -47,5 +47,8 @@
   case Deprecation: 
     delete [] DeprecationData.Message;
     break;
+
+  case ForbiddenType:
+    break;
   }
 }
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index 679f4fe..007d755 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -111,90 +111,110 @@
   return A;
 }
 
+typedef std::pair<unsigned,unsigned> ScopePair;
+
 /// GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a
 /// diagnostic that should be emitted if control goes over it. If not, return 0.
-static std::pair<unsigned,unsigned>
-    GetDiagForGotoScopeDecl(const Decl *D, bool isCPlusPlus) {
+static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) {
   if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
     unsigned InDiag = 0, OutDiag = 0;
     if (VD->getType()->isVariablyModifiedType())
       InDiag = diag::note_protected_by_vla;
 
-    if (VD->hasAttr<BlocksAttr>()) {
-      InDiag = diag::note_protected_by___block;
-      OutDiag = diag::note_exits___block;
-    } else if (VD->hasAttr<CleanupAttr>()) {
-      InDiag = diag::note_protected_by_cleanup;
-      OutDiag = diag::note_exits_cleanup;
-    } else if (isCPlusPlus) {
-      if (!VD->hasLocalStorage())
-        return std::make_pair(InDiag, OutDiag);
-      
-      ASTContext &Context = D->getASTContext();
-      QualType T = Context.getBaseElementType(VD->getType());
-      if (!T->isDependentType()) {
-        // C++0x [stmt.dcl]p3:
-        //   A program that jumps from a point where a variable with automatic
-        //   storage duration is not in scope to a point where it is in scope
-        //   is ill-formed unless the variable has scalar type, class type with
-        //   a trivial default constructor and a trivial destructor, a 
-        //   cv-qualified version of one of these types, or an array of one of
-        //   the preceding types and is declared without an initializer (8.5).
-        // Check whether this is a C++ class.
-        CXXRecordDecl *Record = T->getAsCXXRecordDecl();
-        
-        if (const Expr *Init = VD->getInit()) {
-          bool CallsTrivialConstructor = false;
-          if (Record) {
-            // FIXME: With generalized initializer lists, this may
-            // classify "X x{};" as having no initializer.
-            if (const CXXConstructExpr *Construct 
-                                        = dyn_cast<CXXConstructExpr>(Init))
-              if (const CXXConstructorDecl *Constructor
-                                                = Construct->getConstructor())
-                if ((Context.getLangOptions().CPlusPlus0x
-                       ? Record->hasTrivialDefaultConstructor()
-                       : Record->isPOD()) &&
-                    Constructor->isDefaultConstructor())
-                  CallsTrivialConstructor = true;
-            
-            if (CallsTrivialConstructor && !Record->hasTrivialDestructor())
-              InDiag = diag::note_protected_by_variable_nontriv_destructor;
+    if (VD->hasAttr<BlocksAttr>())
+      return ScopePair(diag::note_protected_by___block,
+                       diag::note_exits___block);
+
+    if (VD->hasAttr<CleanupAttr>())
+      return ScopePair(diag::note_protected_by_cleanup,
+                       diag::note_exits_cleanup);
+
+    if (Context.getLangOptions().ObjCAutoRefCount && VD->hasLocalStorage()) {
+      switch (VD->getType().getObjCLifetime()) {
+      case Qualifiers::OCL_None:
+      case Qualifiers::OCL_ExplicitNone:
+      case Qualifiers::OCL_Autoreleasing:
+        break;
+
+      case Qualifiers::OCL_Strong:
+      case Qualifiers::OCL_Weak:
+        return ScopePair(diag::note_protected_by_objc_lifetime,
+                         diag::note_exits_objc_lifetime);
+      }
+    }
+
+    if (Context.getLangOptions().CPlusPlus && VD->hasLocalStorage()) {
+      // C++0x [stmt.dcl]p3:
+      //   A program that jumps from a point where a variable with automatic
+      //   storage duration is not in scope to a point where it is in scope
+      //   is ill-formed unless the variable has scalar type, class type with
+      //   a trivial default constructor and a trivial destructor, a 
+      //   cv-qualified version of one of these types, or an array of one of
+      //   the preceding types and is declared without an initializer.
+
+      // C++03 [stmt.dcl.p3:
+      //   A program that jumps from a point where a local variable
+      //   with automatic storage duration is not in scope to a point
+      //   where it is in scope is ill-formed unless the variable has
+      //   POD type and is declared without an initializer.
+
+      if (const Expr *init = VD->getInit()) {
+        // We actually give variables of record type (or array thereof)
+        // an initializer even if that initializer only calls a trivial
+        // ctor.  Detect that case.
+        // FIXME: With generalized initializer lists, this may
+        // classify "X x{};" as having no initializer.
+        unsigned inDiagToUse = diag::note_protected_by_variable_init;
+
+        const CXXRecordDecl *record = 0;
+
+        if (const CXXConstructExpr *cce = dyn_cast<CXXConstructExpr>(init)) {
+          const CXXConstructorDecl *ctor = cce->getConstructor();
+          record = ctor->getParent();
+
+          if (ctor->isTrivial() && ctor->isDefaultConstructor()) {
+            if (Context.getLangOptions().CPlusPlus0x) {
+              inDiagToUse = (record->hasTrivialDestructor() ? 0 :
+                        diag::note_protected_by_variable_nontriv_destructor);
+            } else {
+              if (record->isPOD())
+                inDiagToUse = 0;
+            }
           }
-          
-          if (!CallsTrivialConstructor)
-            InDiag = diag::note_protected_by_variable_init;
+        } else if (VD->getType()->isArrayType()) {
+          record = VD->getType()->getBaseElementTypeUnsafe()
+                                ->getAsCXXRecordDecl();
         }
-        
-        // Note whether we have a class with a non-trivial destructor.
-        if (Record && !Record->hasTrivialDestructor())
+
+        if (inDiagToUse)
+          InDiag = inDiagToUse;
+
+        // Also object to indirect jumps which leave scopes with dtors.
+        if (record && !record->hasTrivialDestructor())
           OutDiag = diag::note_exits_dtor;
       }
     }
     
-    return std::make_pair(InDiag, OutDiag);    
+    return ScopePair(InDiag, OutDiag);    
   }
 
   if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
     if (TD->getUnderlyingType()->isVariablyModifiedType())
-      return std::make_pair((unsigned) diag::note_protected_by_vla_typedef, 0);
+      return ScopePair(diag::note_protected_by_vla_typedef, 0);
   }
 
   if (const TypeAliasDecl *TD = dyn_cast<TypeAliasDecl>(D)) {
     if (TD->getUnderlyingType()->isVariablyModifiedType())
-      return std::make_pair((unsigned) diag::note_protected_by_vla_type_alias, 0);
+      return ScopePair(diag::note_protected_by_vla_type_alias, 0);
   }
 
-  return std::make_pair(0U, 0U);
+  return ScopePair(0U, 0U);
 }
 
 /// \brief Build scope information for a declaration that is part of a DeclStmt.
 void JumpScopeChecker::BuildScopeInformation(Decl *D, unsigned &ParentScope) {
-  bool isCPlusPlus = this->S.getLangOptions().CPlusPlus;
-  
   // If this decl causes a new scope, push and switch to it.
-  std::pair<unsigned,unsigned> Diags
-    = GetDiagForGotoScopeDecl(D, isCPlusPlus);
+  std::pair<unsigned,unsigned> Diags = GetDiagForGotoScopeDecl(S.Context, D);
   if (Diags.first || Diags.second) {
     Scopes.push_back(GotoScope(ParentScope, Diags.first, Diags.second,
                                D->getLocation()));
@@ -369,6 +389,18 @@
       continue;
     }
 
+    // Disallow jumps into the protected statement of an @autoreleasepool.
+    if (ObjCAutoreleasePoolStmt *AS = dyn_cast<ObjCAutoreleasePoolStmt>(SubStmt)){
+      // Recursively walk the AST for the @autoreleasepool part, protected by a new
+      // scope.
+      Scopes.push_back(GotoScope(ParentScope,
+                                 diag::note_protected_by_objc_autoreleasepool,
+                                 diag::note_exits_objc_autoreleasepool,
+                                 AS->getAtLoc()));
+      BuildScopeInformation(AS->getSubStmt(), Scopes.size()-1);
+      continue;
+    }
+
     // Recursively walk the AST.
     BuildScopeInformation(SubStmt, ParentScope);
   }
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 8297b31..7d22031 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -143,7 +143,7 @@
     Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
     ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0), 
     PackContext(0), MSStructPragmaOn(false), VisContext(0),
-    LateTemplateParser(0), OpaqueParser(0),
+    ExprNeedsCleanups(0), LateTemplateParser(0), OpaqueParser(0),
     IdResolver(pp.getLangOptions()), CXXTypeInfoDecl(0), MSVCGuidDecl(0),
     GlobalNewDeleteDeclared(false), 
     CompleteTranslationUnit(CompleteTranslationUnit),
@@ -162,7 +162,7 @@
                                        &Context);
 
   ExprEvalContexts.push_back(
-                  ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0));  
+        ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0, false));
 
   FunctionScopes.push_back(new FunctionScopeInfo(Diags));
 }
@@ -202,6 +202,32 @@
     ExternalSema->ForgetSema();
 }
 
+
+/// makeUnavailableInSystemHeader - There is an error in the current
+/// context.  If we're still in a system header, and we can plausibly
+/// make the relevant declaration unavailable instead of erroring, do
+/// so and return true.
+bool Sema::makeUnavailableInSystemHeader(SourceLocation loc,
+                                         llvm::StringRef msg) {
+  // If we're not in a function, it's an error.
+  FunctionDecl *fn = dyn_cast<FunctionDecl>(CurContext);
+  if (!fn) return false;
+
+  // If we're in template instantiation, it's an error.
+  if (!ActiveTemplateInstantiations.empty())
+    return false;
+  
+  // If that function's not in a system header, it's an error.
+  if (!Context.getSourceManager().isInSystemHeader(loc))
+    return false;
+
+  // If the function is already unavailable, it's not an error.
+  if (fn->hasAttr<UnavailableAttr>()) return true;
+
+  fn->addAttr(new (Context) UnavailableAttr(loc, Context, msg));
+  return true;
+}
+
 ASTMutationListener *Sema::getASTMutationListener() const {
   return getASTConsumer().GetASTMutationListener();
 }
@@ -211,13 +237,17 @@
 /// The result is of the given category.
 ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
                                    CastKind Kind, ExprValueKind VK,
-                                   const CXXCastPath *BasePath) {
+                                   const CXXCastPath *BasePath,
+                                   CheckedConversionKind CCK) {
   QualType ExprTy = Context.getCanonicalType(E->getType());
   QualType TypeTy = Context.getCanonicalType(Ty);
 
   if (ExprTy == TypeTy)
     return Owned(E);
 
+  if (getLangOptions().ObjCAutoRefCount)
+    CheckObjCARCConversion(SourceRange(), Ty, E, CCK);
+
   // If this is a derived-to-base cast to a through a virtual base, we
   // need a vtable.
   if (Kind == CK_DerivedToBase && 
@@ -729,8 +759,8 @@
 
 /// \brief Determine whether any errors occurred within this function/method/
 /// block.
-bool Sema::hasAnyErrorsInThisFunction() const {
-  return getCurFunction()->ErrorTrap.hasErrorOccurred();
+bool Sema::hasAnyUnrecoverableErrorsInThisFunction() const {
+  return getCurFunction()->ErrorTrap.hasUnrecoverableErrorOccurred();
 }
 
 BlockScopeInfo *Sema::getCurBlock() {
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index e46ad5b..0b3083a 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -63,7 +63,8 @@
                              CastKind &Kind,
                              CXXCastPath &BasePath);
 
-static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType);
+static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
+                               bool CheckCVR, bool CheckObjCLifetime);
 
 // The Try functions attempt a specific way of casting. If they succeed, they
 // return TC_Success. If their way of casting is not appropriate for the given
@@ -109,12 +110,14 @@
                                                CXXCastPath &BasePath);
 
 static TryCastResult TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr,
-                                           QualType DestType, bool CStyle,
+                                           QualType DestType, 
+                                           Sema::CheckedConversionKind CCK,
                                            const SourceRange &OpRange,
                                            unsigned &msg,
                                            CastKind &Kind);
 static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
-                                   QualType DestType, bool CStyle,
+                                   QualType DestType, 
+                                   Sema::CheckedConversionKind CCK,
                                    const SourceRange &OpRange,
                                    unsigned &msg,
                                    CastKind &Kind,
@@ -248,8 +251,10 @@
 
   InitializedEntity entity = InitializedEntity::InitializeTemporary(destType);
   InitializationKind initKind
-    = InitializationKind::CreateCast(/*type range?*/ range,
-                                     (CT == CT_CStyle || CT == CT_Functional));
+    = (CT == CT_CStyle)? InitializationKind::CreateCStyleCast(range.getBegin(),
+                                                              range)
+    : (CT == CT_Functional)? InitializationKind::CreateFunctionalCast(range)
+    : InitializationKind::CreateCast(/*type range?*/ range);
   InitializationSequence sequence(S, entity, initKind, &src, 1);
 
   assert(sequence.Failed() && "initialization succeeded on second try?");
@@ -373,8 +378,19 @@
 /// DestType casts away constness as defined in C++ 5.2.11p8ff. This is used by
 /// the cast checkers.  Both arguments must denote pointer (possibly to member)
 /// types.
+///
+/// \param CheckCVR Whether to check for const/volatile/restrict qualifiers.
+///
+/// \param CheckObjCLifetime Whether to check Objective-C lifetime qualifiers.
 static bool
-CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) {
+CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
+                   bool CheckCVR, bool CheckObjCLifetime) {
+  // If the only checking we care about is for Objective-C lifetime qualifiers,
+  // and we're not in ARC mode, there's nothing to check.
+  if (!CheckCVR && CheckObjCLifetime && 
+      !Self.Context.getLangOptions().ObjCAutoRefCount)
+    return false;
+    
   // Casting away constness is defined in C++ 5.2.11p8 with reference to
   // C++ 4.4. We piggyback on Sema::IsQualificationConversion for this, since
   // the rules are non-trivial. So first we construct Tcv *...cv* as described
@@ -394,13 +410,23 @@
   // purpose of this check, because other qualifiers (address spaces, 
   // Objective-C GC, etc.) are part of the type's identity.
   while (UnwrapDissimilarPointerTypes(UnwrappedSrcType, UnwrappedDestType)) {
-    Qualifiers SrcQuals;
+    // Determine the relevant qualifiers at this level.
+    Qualifiers SrcQuals, DestQuals;
     Self.Context.getUnqualifiedArrayType(UnwrappedSrcType, SrcQuals);
-    cv1.push_back(Qualifiers::fromCVRMask(SrcQuals.getCVRQualifiers()));
-    
-    Qualifiers DestQuals;
     Self.Context.getUnqualifiedArrayType(UnwrappedDestType, DestQuals);
-    cv2.push_back(Qualifiers::fromCVRMask(DestQuals.getCVRQualifiers()));
+    
+    Qualifiers RetainedSrcQuals, RetainedDestQuals;
+    if (CheckCVR) {
+      RetainedSrcQuals.setCVRQualifiers(SrcQuals.getCVRQualifiers());
+      RetainedDestQuals.setCVRQualifiers(DestQuals.getCVRQualifiers());
+    }
+    
+    if (CheckObjCLifetime &&
+        !DestQuals.compatiblyIncludesObjCLifetime(SrcQuals))
+      return true;
+    
+    cv1.push_back(RetainedSrcQuals);
+    cv2.push_back(RetainedDestQuals);
   }
   if (cv1.empty())
     return false;
@@ -420,8 +446,10 @@
   }
 
   // Test if they're compatible.
+  bool ObjCLifetimeConversion;
   return SrcConstruct != DestConstruct &&
-    !Self.IsQualificationConversion(SrcConstruct, DestConstruct, false);
+    !Self.IsQualificationConversion(SrcConstruct, DestConstruct, false,
+                                    ObjCLifetimeConversion);
 }
 
 /// CheckDynamicCast - Check that a dynamic_cast\<DestType\>(SrcExpr) is valid.
@@ -595,9 +623,10 @@
   }
 
   unsigned msg = diag::err_bad_cxx_cast_generic;
-  if (TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange,
-                         msg, Kind)
-      != TC_Success && msg != 0)
+  TryCastResult tcr = 
+    TryReinterpretCast(Self, SrcExpr, DestType, 
+                       /*CStyle*/false, OpRange, msg, Kind);
+  if (tcr != TC_Success && msg != 0)
   {
     if (SrcExpr.isInvalid()) // if conversion failed, don't report another error
       return;
@@ -611,7 +640,10 @@
     } else {
       diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(), DestType);
     }
-  }    
+  } else if (tcr == TC_Success && Self.getLangOptions().ObjCAutoRefCount) {
+    Self.CheckObjCARCConversion(OpRange, DestType,
+                                SrcExpr.get(), Sema::CCK_OtherCast);
+  }
 }
 
 
@@ -654,8 +686,10 @@
   }
 
   unsigned msg = diag::err_bad_cxx_cast_generic;
-  if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg,
-                    Kind, BasePath) != TC_Success && msg != 0) {
+  TryCastResult tcr
+    = TryStaticCast(Self, SrcExpr, DestType, Sema::CCK_OtherCast, OpRange, msg,
+                    Kind, BasePath);
+  if (tcr != TC_Success && msg != 0) {
     if (SrcExpr.isInvalid())
       return;
     if (SrcExpr.get()->getType() == Self.Context.OverloadTy) {
@@ -667,6 +701,12 @@
     } else {
       diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr.get(), DestType);
     }
+  } else if (tcr == TC_Success) {
+    if (Kind == CK_BitCast)
+      Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange);
+    if (Self.getLangOptions().ObjCAutoRefCount)
+      Self.CheckObjCARCConversion(OpRange, DestType,
+                                  SrcExpr.get(), Sema::CCK_OtherCast);
   }
   else if (Kind == CK_BitCast)
     Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange);
@@ -676,10 +716,15 @@
 /// possible. If @p CStyle, ignore access restrictions on hierarchy casting
 /// and casting away constness.
 static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
-                                   QualType DestType, bool CStyle,
+                                   QualType DestType, 
+                                   Sema::CheckedConversionKind CCK,
                                    const SourceRange &OpRange, unsigned &msg,
                                    CastKind &Kind,
                                    CXXCastPath &BasePath) {
+  // Determine whether we have the semantics of a C-style cast.
+  bool CStyle 
+    = (CCK == Sema::CCK_CStyleCast || CCK == Sema::CCK_FunctionalCast);
+  
   // The order the tests is not entirely arbitrary. There is one conversion
   // that can be handled in two different ways. Given:
   // struct A {};
@@ -715,7 +760,7 @@
 
   // C++ 5.2.9p2: An expression e can be explicitly converted to a type T
   //   [...] if the declaration "T t(e);" is well-formed, [...].
-  tcr = TryStaticImplicitCast(Self, SrcExpr, DestType, CStyle, OpRange, msg,
+  tcr = TryStaticImplicitCast(Self, SrcExpr, DestType, CCK, OpRange, msg,
                               Kind);
   if (SrcExpr.isInvalid())
     return TC_Failed;
@@ -792,10 +837,20 @@
         QualType DestPointee = DestPointer->getPointeeType();
         if (DestPointee->isIncompleteOrObjectType()) {
           // This is definitely the intended conversion, but it might fail due
-          // to a const violation.
-          if (!CStyle && !DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) {
-            msg = diag::err_bad_cxx_cast_qualifiers_away;
-            return TC_Failed;
+          // to a qualifier violation. Note that we permit Objective-C lifetime
+          // and GC qualifier mismatches here.
+          if (!CStyle) {
+            Qualifiers DestPointeeQuals = DestPointee.getQualifiers();
+            Qualifiers SrcPointeeQuals = SrcPointee.getQualifiers();
+            DestPointeeQuals.removeObjCGCAttr();
+            DestPointeeQuals.removeObjCLifetime();
+            SrcPointeeQuals.removeObjCGCAttr();
+            SrcPointeeQuals.removeObjCLifetime();
+            if (DestPointeeQuals != SrcPointeeQuals &&
+                !DestPointeeQuals.compatiblyIncludes(SrcPointeeQuals)) {
+              msg = diag::err_bad_cxx_cast_qualifiers_away;
+              return TC_Failed;
+            }
           }
           Kind = CK_BitCast;
           return TC_Success;
@@ -845,6 +900,7 @@
   // FIXME: Should allow casting away constness if CStyle.
   bool DerivedToBase;
   bool ObjCConversion;
+  bool ObjCLifetimeConversion;
   QualType FromType = SrcExpr->getType();
   QualType ToType = R->getPointeeType();
   if (CStyle) {
@@ -854,8 +910,9 @@
   
   if (Self.CompareReferenceRelationship(SrcExpr->getLocStart(),
                                         ToType, FromType,
-                                        DerivedToBase, ObjCConversion) <
-        Sema::Ref_Compatible_With_Added_Qualification) {
+                                        DerivedToBase, ObjCConversion,
+                                        ObjCLifetimeConversion) 
+        < Sema::Ref_Compatible_With_Added_Qualification) {
     msg = diag::err_bad_lvalue_to_rvalue_cast;
     return TC_Failed;
   }
@@ -1172,7 +1229,8 @@
 ///   @c static_cast if the declaration "T t(e);" is well-formed [...].
 TryCastResult
 TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
-                      bool CStyle, const SourceRange &OpRange, unsigned &msg,
+                      Sema::CheckedConversionKind CCK, 
+                      const SourceRange &OpRange, unsigned &msg,
                       CastKind &Kind) {
   if (DestType->isRecordType()) {
     if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
@@ -1184,7 +1242,11 @@
   
   InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType);
   InitializationKind InitKind
-    = InitializationKind::CreateCast(/*FIXME:*/OpRange, CStyle);    
+    = (CCK == Sema::CCK_CStyleCast)
+        ? InitializationKind::CreateCStyleCast(OpRange.getBegin(), OpRange)
+    : (CCK == Sema::CCK_FunctionalCast)
+        ? InitializationKind::CreateFunctionalCast(OpRange)
+    : InitializationKind::CreateCast(OpRange);
   Expr *SrcExprRaw = SrcExpr.get();
   InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExprRaw, 1);
 
@@ -1193,7 +1255,8 @@
   // There is no other way that works.
   // On the other hand, if we're checking a C-style cast, we've still got
   // the reinterpret_cast way.
-  
+  bool CStyle 
+    = (CCK == Sema::CCK_CStyleCast || CCK == Sema::CCK_FunctionalCast);
   if (InitSeq.Failed() && (CStyle || !DestType->isReferenceType()))
     return TC_NotApplicable;
     
@@ -1428,7 +1491,8 @@
     //   constness.
     // A reinterpret_cast followed by a const_cast can, though, so in C-style,
     // we accept it.
-    if (!CStyle && CastsAwayConstness(Self, SrcType, DestType)) {
+    if (CastsAwayConstness(Self, SrcType, DestType, /*CheckCVR=*/!CStyle,
+                           /*CheckObjCLifetime=*/CStyle)) {
       msg = diag::err_bad_cxx_cast_qualifiers_away;
       return TC_Failed;
     }
@@ -1543,7 +1607,8 @@
 
   // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away constness.
   // The C-style cast operator can.
-  if (!CStyle && CastsAwayConstness(Self, SrcType, DestType)) {
+  if (CastsAwayConstness(Self, SrcType, DestType, /*CheckCVR=*/!CStyle,
+                         /*CheckObjCLifetime=*/CStyle)) {
     msg = diag::err_bad_cxx_cast_qualifiers_away;
     return TC_Failed;
   }
@@ -1675,11 +1740,14 @@
   if (tcr == TC_Success)
     Kind = CK_NoOp;
 
+  Sema::CheckedConversionKind CCK
+    = FunctionalStyle? Sema::CCK_FunctionalCast
+                     : Sema::CCK_CStyleCast;
   if (tcr == TC_NotApplicable) {
     // ... or if that is not possible, a static_cast, ignoring const, ...
     ExprResult CastExprRes = Owned(CastExpr);
-    tcr = TryStaticCast(*this, CastExprRes, CastTy, /*CStyle*/true, R, msg,
-                        Kind, BasePath);
+    tcr = TryStaticCast(*this, CastExprRes, CastTy, CCK, R, msg, Kind, 
+                        BasePath);
     if (CastExprRes.isInvalid())
       return ExprError();
     CastExpr = CastExprRes.take();
@@ -1694,6 +1762,9 @@
     }
   }
 
+  if (getLangOptions().ObjCAutoRefCount && tcr == TC_Success)
+    CheckObjCARCConversion(R, CastTy, CastExpr, CCK);
+
   if (tcr != TC_Success && msg != 0) {
     if (CastExpr->getType() == Context.OverloadTy) {
       DeclAccessPair Found;
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 389dd91..d45ebf9 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -22,6 +22,7 @@
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExprObjC.h"
+#include "clang/AST/EvaluatedExprVisitor.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/StmtCXX.h"
 #include "clang/AST/StmtObjC.h"
@@ -382,14 +383,14 @@
   // casts here.
   // FIXME: We don't allow floating point scalars as input.
   Expr *FirstArg = TheCall->getArg(0);
-  if (!FirstArg->getType()->isPointerType()) {
+  const PointerType *pointerType = FirstArg->getType()->getAs<PointerType>();
+  if (!pointerType) {
     Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer)
       << FirstArg->getType() << FirstArg->getSourceRange();
     return ExprError();
   }
 
-  QualType ValType =
-    FirstArg->getType()->getAs<PointerType>()->getPointeeType();
+  QualType ValType = pointerType->getPointeeType();
   if (!ValType->isIntegerType() && !ValType->isAnyPointerType() &&
       !ValType->isBlockPointerType()) {
     Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer_intptr)
@@ -397,6 +398,20 @@
     return ExprError();
   }
 
+  switch (ValType.getObjCLifetime()) {
+  case Qualifiers::OCL_None:
+  case Qualifiers::OCL_ExplicitNone:
+    // okay
+    break;
+
+  case Qualifiers::OCL_Weak:
+  case Qualifiers::OCL_Strong:
+  case Qualifiers::OCL_Autoreleasing:
+    Diag(DRE->getLocStart(), diag::err_arc_atomic_lifetime)
+      << ValType << FirstArg->getSourceRange();
+    return ExprError();
+  }
+
   // The majority of builtins return a value, but a few have special return
   // types, so allow them to override appropriately below.
   QualType ResultType = ValType;
@@ -518,7 +533,8 @@
     CastKind Kind = CK_Invalid;
     ExprValueKind VK = VK_RValue;
     CXXCastPath BasePath;
-    Arg = CheckCastTypes(Arg.get()->getSourceRange(), ValType, Arg.take(), Kind, VK, BasePath);
+    Arg = CheckCastTypes(Arg.get()->getLocStart(), Arg.get()->getSourceRange(), 
+                         ValType, Arg.take(), Kind, VK, BasePath);
     if (Arg.isInvalid())
       return ExprError();
 
@@ -1849,6 +1865,7 @@
     QualType DestTy = Dest->getType();
     if (const PointerType *DestPtrTy = DestTy->getAs<PointerType>()) {
       QualType PointeeTy = DestPtrTy->getPointeeType();
+
       if (PointeeTy->isVoidType())
         continue;
 
@@ -1863,16 +1880,22 @@
         break;
       }
 
+      unsigned DiagID;
+
       // Always complain about dynamic classes.
-      if (isDynamicClassType(PointeeTy)) {
-        DiagRuntimeBehavior(
-          Dest->getExprLoc(), Dest,
-          PDiag(diag::warn_dyn_class_memaccess)
-            << ArgIdx << FnName << PointeeTy 
-            << Call->getCallee()->getSourceRange());
-      } else {
+      if (isDynamicClassType(PointeeTy))
+        DiagID = diag::warn_dyn_class_memaccess;
+      else if (PointeeTy.hasNonTrivialObjCLifetime() && 
+               !FnName->isStr("memset"))
+        DiagID = diag::warn_arc_object_memaccess;
+      else
         continue;
-      }
+
+      DiagRuntimeBehavior(
+        Dest->getExprLoc(), Dest,
+        PDiag(DiagID)
+          << ArgIdx << FnName << PointeeTy 
+          << Call->getCallee()->getSourceRange());
 
       DiagRuntimeBehavior(
         Dest->getExprLoc(), Dest,
@@ -1899,7 +1922,8 @@
 
   // Perform checking for returned stack addresses, local blocks,
   // label addresses or references to temporaries.
-  if (lhsType->isPointerType() || lhsType->isBlockPointerType()) {
+  if (lhsType->isPointerType() ||
+      (!getLangOptions().ObjCAutoRefCount && lhsType->isBlockPointerType())) {
     stackE = EvalAddr(RetValExp, refVars);
   } else if (lhsType->isReferenceType()) {
     stackE = EvalVal(RetValExp, refVars);
@@ -2070,7 +2094,8 @@
   // pointer values, and pointer-to-pointer conversions.
   case Stmt::ImplicitCastExprClass:
   case Stmt::CStyleCastExprClass:
-  case Stmt::CXXFunctionalCastExprClass: {
+  case Stmt::CXXFunctionalCastExprClass:
+  case Stmt::ObjCBridgedCastExprClass: {
     Expr* SubExpr = cast<CastExpr>(E)->getSubExpr();
     QualType T = SubExpr->getType();
 
@@ -3385,3 +3410,232 @@
     }
   }
 }
+
+//===--- CHECK: Objective-C retain cycles ----------------------------------//
+
+namespace {
+  struct RetainCycleOwner {
+    RetainCycleOwner() : Variable(0), Indirect(false) {}
+    VarDecl *Variable;
+    SourceRange Range;
+    SourceLocation Loc;
+    bool Indirect;
+
+    void setLocsFrom(Expr *e) {
+      Loc = e->getExprLoc();
+      Range = e->getSourceRange();
+    }
+  };
+}
+
+/// Consider whether capturing the given variable can possibly lead to
+/// a retain cycle.
+static bool considerVariable(VarDecl *var, Expr *ref, RetainCycleOwner &owner) {
+  // In ARC, it's captured strongly iff the variable has __strong
+  // lifetime.  In MRR, it's captured strongly if the variable is
+  // __block and has an appropriate type.
+  if (var->getType().getObjCLifetime() != Qualifiers::OCL_Strong)
+    return false;
+
+  owner.Variable = var;
+  owner.setLocsFrom(ref);
+  return true;
+}
+
+static bool findRetainCycleOwner(Expr *e, RetainCycleOwner &owner) {
+  while (true) {
+    e = e->IgnoreParens();
+    if (CastExpr *cast = dyn_cast<CastExpr>(e)) {
+      switch (cast->getCastKind()) {
+      case CK_BitCast:
+      case CK_LValueBitCast:
+      case CK_LValueToRValue:
+        e = cast->getSubExpr();
+        continue;
+
+      case CK_GetObjCProperty: {
+        // Bail out if this isn't a strong explicit property.
+        const ObjCPropertyRefExpr *pre = cast->getSubExpr()->getObjCProperty();
+        if (pre->isImplicitProperty()) return false;
+        ObjCPropertyDecl *property = pre->getExplicitProperty();
+        if (!(property->getPropertyAttributes() &
+              (ObjCPropertyDecl::OBJC_PR_retain |
+               ObjCPropertyDecl::OBJC_PR_copy |
+               ObjCPropertyDecl::OBJC_PR_strong)) &&
+            !(property->getPropertyIvarDecl() &&
+              property->getPropertyIvarDecl()->getType()
+                .getObjCLifetime() == Qualifiers::OCL_Strong))
+          return false;
+
+        owner.Indirect = true;
+        e = const_cast<Expr*>(pre->getBase());
+        continue;
+      }
+        
+      default:
+        return false;
+      }
+    }
+
+    if (ObjCIvarRefExpr *ref = dyn_cast<ObjCIvarRefExpr>(e)) {
+      ObjCIvarDecl *ivar = ref->getDecl();
+      if (ivar->getType().getObjCLifetime() != Qualifiers::OCL_Strong)
+        return false;
+
+      // Try to find a retain cycle in the base.
+      if (!findRetainCycleOwner(ref->getBase(), owner))
+        return false;
+
+      if (ref->isFreeIvar()) owner.setLocsFrom(ref);
+      owner.Indirect = true;
+      return true;
+    }
+
+    if (DeclRefExpr *ref = dyn_cast<DeclRefExpr>(e)) {
+      VarDecl *var = dyn_cast<VarDecl>(ref->getDecl());
+      if (!var) return false;
+      return considerVariable(var, ref, owner);
+    }
+
+    if (BlockDeclRefExpr *ref = dyn_cast<BlockDeclRefExpr>(e)) {
+      owner.Variable = ref->getDecl();
+      owner.setLocsFrom(ref);
+      return true;
+    }
+
+    if (MemberExpr *member = dyn_cast<MemberExpr>(e)) {
+      if (member->isArrow()) return false;
+
+      // Don't count this as an indirect ownership.
+      e = member->getBase();
+      continue;
+    }
+
+    // Array ivars?
+
+    return false;
+  }
+}
+
+namespace {
+  struct FindCaptureVisitor : EvaluatedExprVisitor<FindCaptureVisitor> {
+    FindCaptureVisitor(ASTContext &Context, VarDecl *variable)
+      : EvaluatedExprVisitor<FindCaptureVisitor>(Context),
+        Variable(variable), Capturer(0) {}
+
+    VarDecl *Variable;
+    Expr *Capturer;
+
+    void VisitDeclRefExpr(DeclRefExpr *ref) {
+      if (ref->getDecl() == Variable && !Capturer)
+        Capturer = ref;
+    }
+
+    void VisitBlockDeclRefExpr(BlockDeclRefExpr *ref) {
+      if (ref->getDecl() == Variable && !Capturer)
+        Capturer = ref;
+    }
+
+    void VisitObjCIvarRefExpr(ObjCIvarRefExpr *ref) {
+      if (Capturer) return;
+      Visit(ref->getBase());
+      if (Capturer && ref->isFreeIvar())
+        Capturer = ref;
+    }
+
+    void VisitBlockExpr(BlockExpr *block) {
+      // Look inside nested blocks 
+      if (block->getBlockDecl()->capturesVariable(Variable))
+        Visit(block->getBlockDecl()->getBody());
+    }
+  };
+}
+
+/// Check whether the given argument is a block which captures a
+/// variable.
+static Expr *findCapturingExpr(Sema &S, Expr *e, RetainCycleOwner &owner) {
+  assert(owner.Variable && owner.Loc.isValid());
+
+  e = e->IgnoreParenCasts();
+  BlockExpr *block = dyn_cast<BlockExpr>(e);
+  if (!block || !block->getBlockDecl()->capturesVariable(owner.Variable))
+    return 0;
+
+  FindCaptureVisitor visitor(S.Context, owner.Variable);
+  visitor.Visit(block->getBlockDecl()->getBody());
+  return visitor.Capturer;
+}
+
+static void diagnoseRetainCycle(Sema &S, Expr *capturer,
+                                RetainCycleOwner &owner) {
+  assert(capturer);
+  assert(owner.Variable && owner.Loc.isValid());
+
+  S.Diag(capturer->getExprLoc(), diag::warn_arc_retain_cycle)
+    << owner.Variable << capturer->getSourceRange();
+  S.Diag(owner.Loc, diag::note_arc_retain_cycle_owner)
+    << owner.Indirect << owner.Range;
+}
+
+/// Check for a keyword selector that starts with the word 'add' or
+/// 'set'.
+static bool isSetterLikeSelector(Selector sel) {
+  if (sel.isUnarySelector()) return false;
+
+  llvm::StringRef str = sel.getNameForSlot(0);
+  while (!str.empty() && str.front() == '_') str = str.substr(1);
+  if (str.startswith("set") || str.startswith("add"))
+    str = str.substr(3);
+  else
+    return false;
+
+  if (str.empty()) return true;
+  return !islower(str.front());
+}
+
+/// Check a message send to see if it's likely to cause a retain cycle.
+void Sema::checkRetainCycles(ObjCMessageExpr *msg) {
+  // Only check instance methods whose selector looks like a setter.
+  if (!msg->isInstanceMessage() || !isSetterLikeSelector(msg->getSelector()))
+    return;
+
+  // Try to find a variable that the receiver is strongly owned by.
+  RetainCycleOwner owner;
+  if (msg->getReceiverKind() == ObjCMessageExpr::Instance) {
+    if (!findRetainCycleOwner(msg->getInstanceReceiver(), owner))
+      return;
+  } else {
+    assert(msg->getReceiverKind() == ObjCMessageExpr::SuperInstance);
+    owner.Variable = getCurMethodDecl()->getSelfDecl();
+    owner.Loc = msg->getSuperLoc();
+    owner.Range = msg->getSuperLoc();
+  }
+
+  // Check whether the receiver is captured by any of the arguments.
+  for (unsigned i = 0, e = msg->getNumArgs(); i != e; ++i)
+    if (Expr *capturer = findCapturingExpr(*this, msg->getArg(i), owner))
+      return diagnoseRetainCycle(*this, capturer, owner);
+}
+
+/// Check a property assign to see if it's likely to cause a retain cycle.
+void Sema::checkRetainCycles(Expr *receiver, Expr *argument) {
+  RetainCycleOwner owner;
+  if (!findRetainCycleOwner(receiver, owner))
+    return;
+
+  if (Expr *capturer = findCapturingExpr(*this, argument, owner))
+    diagnoseRetainCycle(*this, capturer, owner);
+}
+
+void Sema::checkUnsafeAssigns(SourceLocation Loc,
+                              QualType LHS, Expr *RHS) {
+  Qualifiers::ObjCLifetime LT = LHS.getObjCLifetime();
+  if (LT != Qualifiers::OCL_Weak && LT != Qualifiers::OCL_ExplicitNone)
+    return;
+  if (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS))
+    if (cast->getCastKind() == CK_ObjCConsumeObject)
+      Diag(Loc, diag::warn_arc_retained_assign)
+        << (LT == Qualifiers::OCL_ExplicitNone) 
+        << RHS->getSourceRange();
+}
+
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index e328eeb..69b3859 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -1676,6 +1676,34 @@
     // Fall through: conditions and statements can have expressions.
 
   case Sema::PCC_ParenthesizedExpression:
+    if (SemaRef.getLangOptions().ObjCAutoRefCount &&
+        CCC == Sema::PCC_ParenthesizedExpression) {
+      // (__bridge <type>)<expression>
+      Builder.AddTypedTextChunk("__bridge");
+      Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+      Builder.AddPlaceholderChunk("type");
+      Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      Builder.AddPlaceholderChunk("expression");
+      Results.AddResult(Result(Builder.TakeString()));      
+
+      // (__bridge_transfer <Objective-C type>)<expression>
+      Builder.AddTypedTextChunk("__bridge_transfer");
+      Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+      Builder.AddPlaceholderChunk("Objective-C type");
+      Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      Builder.AddPlaceholderChunk("expression");
+      Results.AddResult(Result(Builder.TakeString()));      
+
+      // (__bridge_retained <CF type>)<expression>
+      Builder.AddTypedTextChunk("__bridge_retained");
+      Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+      Builder.AddPlaceholderChunk("CF type");
+      Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      Builder.AddPlaceholderChunk("expression");
+      Results.AddResult(Result(Builder.TakeString()));      
+    }
+    // Fall through
+
   case Sema::PCC_Expression: {
     if (SemaRef.getLangOptions().CPlusPlus) {
       // 'this', if we're in a non-static member function.
@@ -1828,7 +1856,8 @@
                                            CodeCompletionAllocator &Allocator) {
   PrintingPolicy Policy(Context.PrintingPolicy);
   Policy.AnonymousTagLocations = false;
-
+  Policy.SuppressStrongLifetime = true;
+  
   if (!T.getLocalQualifiers()) {
     // Built-in type names are constant strings.
     if (const BuiltinType *BT = dyn_cast<BuiltinType>(T))
@@ -1878,9 +1907,9 @@
     T = Context.getTypeDeclType(cast<TypeDecl>(Enumerator->getDeclContext()));
   else if (isa<UnresolvedUsingValueDecl>(ND)) {
     /* Do nothing: ignore unresolved using declarations*/
-  } else if (ValueDecl *Value = dyn_cast<ValueDecl>(ND))
+  } else if (ValueDecl *Value = dyn_cast<ValueDecl>(ND)) {
     T = Value->getType();
-  else if (ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND))
+  } else if (ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND))
     T = Property->getType();
   
   if (T.isNull() || Context.hasSameType(T, Context.DependentTy))
@@ -1907,6 +1936,10 @@
 static std::string FormatFunctionParameter(ASTContext &Context,
                                            ParmVarDecl *Param,
                                            bool SuppressName = false) {
+  PrintingPolicy Policy(Context.PrintingPolicy);
+  Policy.AnonymousTagLocations = false;
+  Policy.SuppressStrongLifetime = true;
+
   bool ObjCMethodParam = isa<ObjCMethodDecl>(Param->getDeclContext());
   if (Param->getType()->isDependentType() ||
       !Param->getType()->isBlockPointerType()) {
@@ -1917,8 +1950,7 @@
     if (Param->getIdentifier() && !ObjCMethodParam && !SuppressName)
       Result = Param->getIdentifier()->getName();
     
-    Param->getType().getAsStringInternal(Result, 
-                                         Context.PrintingPolicy);
+    Param->getType().getAsStringInternal(Result, Policy);
     
     if (ObjCMethodParam) {
       Result = "(" + Result;
@@ -1968,8 +2000,7 @@
     // We were unable to find a FunctionProtoTypeLoc with parameter names
     // for the block; just use the parameter type as a placeholder.
     std::string Result;
-    Param->getType().getUnqualifiedType().
-                            getAsStringInternal(Result, Context.PrintingPolicy);
+    Param->getType().getUnqualifiedType().getAsStringInternal(Result, Policy);
     
     if (ObjCMethodParam) {
       Result = "(" + Result;
@@ -1986,7 +2017,7 @@
   std::string Result;
   QualType ResultType = Block->getTypePtr()->getResultType();
   if (!ResultType->isVoidType())
-    ResultType.getAsStringInternal(Result, Context.PrintingPolicy);
+    ResultType.getAsStringInternal(Result, Policy);
   
   Result = '^' + Result;
   if (!BlockProto || Block->getNumArgs() == 0) {
@@ -2071,6 +2102,9 @@
                                        unsigned MaxParameters = 0,
                                        unsigned Start = 0,
                                        bool InDefaultArg = false) {
+  PrintingPolicy Policy(Context.PrintingPolicy);
+  Policy.AnonymousTagLocations = false;
+
   typedef CodeCompletionString::Chunk Chunk;
   bool FirstParameter = true;
   
@@ -2098,8 +2132,7 @@
                                     = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
       if (NTTP->getIdentifier())
         PlaceholderStr = NTTP->getIdentifier()->getName();
-      NTTP->getType().getAsStringInternal(PlaceholderStr, 
-                                          Context.PrintingPolicy);
+      NTTP->getType().getAsStringInternal(PlaceholderStr, Policy);
       HasDefaultArg = NTTP->hasDefaultArgument();
     } else {
       assert(isa<TemplateTemplateParmDecl>(*P));
@@ -2286,6 +2319,10 @@
   typedef CodeCompletionString::Chunk Chunk;
   CodeCompletionBuilder Result(Allocator, Priority, Availability);
   
+  PrintingPolicy Policy(S.Context.PrintingPolicy);
+  Policy.AnonymousTagLocations = false;
+  Policy.SuppressStrongLifetime = true;
+
   if (Kind == RK_Pattern) {
     Pattern->Priority = Priority;
     Pattern->Availability = Availability;
@@ -2470,7 +2507,7 @@
       if ((*P)->getType()->isBlockPointerType() && !DeclaringEntity)
         Arg = FormatFunctionParameter(S.Context, *P, true);
       else {
-        (*P)->getType().getAsStringInternal(Arg, S.Context.PrintingPolicy);
+        (*P)->getType().getAsStringInternal(Arg, Policy);
         Arg = "(" + Arg + ")";
         if (IdentifierInfo *II = (*P)->getIdentifier())
           if (DeclaringEntity || AllParametersAreInformative)
@@ -2519,7 +2556,10 @@
                                                                Sema &S,
                                      CodeCompletionAllocator &Allocator) const {
   typedef CodeCompletionString::Chunk Chunk;
-  
+  PrintingPolicy Policy(S.Context.PrintingPolicy);
+  Policy.AnonymousTagLocations = false;
+  Policy.SuppressStrongLifetime = true;
+
   // FIXME: Set priority, availability appropriately.
   CodeCompletionBuilder Result(Allocator, 1, CXAvailability_Available);
   FunctionDecl *FDecl = getFunction();
@@ -2545,7 +2585,7 @@
   else
     Result.AddTextChunk(
          Result.getAllocator().CopyString(
-                Proto->getResultType().getAsString(S.Context.PrintingPolicy)));
+                                  Proto->getResultType().getAsString(Policy)));
   
   Result.AddChunk(Chunk(CodeCompletionString::CK_LeftParen));
   unsigned NumParams = FDecl? FDecl->getNumParams() : Proto->getNumArgs();
@@ -2563,7 +2603,7 @@
       ArgType = Proto->getArgType(I);
     }
     
-    ArgType.getAsStringInternal(ArgString, S.Context.PrintingPolicy);
+    ArgType.getAsStringInternal(ArgString, Policy);
     
     if (I == CurrentArg)
       Result.AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter, 
@@ -3786,6 +3826,10 @@
 void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD,
                                               CXXCtorInitializer** Initializers,
                                               unsigned NumInitializers) {
+  PrintingPolicy Policy(Context.PrintingPolicy);
+  Policy.AnonymousTagLocations = false;
+  Policy.SuppressStrongLifetime = true;
+
   CXXConstructorDecl *Constructor
     = static_cast<CXXConstructorDecl *>(ConstructorD);
   if (!Constructor)
@@ -3825,7 +3869,7 @@
     
     Builder.AddTypedTextChunk(
                Results.getAllocator().CopyString(
-                          Base->getType().getAsString(Context.PrintingPolicy)));
+                          Base->getType().getAsString(Policy)));
     Builder.AddChunk(CodeCompletionString::CK_LeftParen);
     Builder.AddPlaceholderChunk("args");
     Builder.AddChunk(CodeCompletionString::CK_RightParen);
@@ -3850,7 +3894,7 @@
     
     Builder.AddTypedTextChunk(
                Builder.getAllocator().CopyString(
-                          Base->getType().getAsString(Context.PrintingPolicy)));
+                          Base->getType().getAsString(Policy)));
     Builder.AddChunk(CodeCompletionString::CK_LeftParen);
     Builder.AddPlaceholderChunk("args");
     Builder.AddChunk(CodeCompletionString::CK_RightParen);
@@ -4126,18 +4170,24 @@
   if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
       (Attributes & (ObjCDeclSpec::DQ_PR_readwrite |
                      ObjCDeclSpec::DQ_PR_assign |
+                     ObjCDeclSpec::DQ_PR_unsafe_unretained |
                      ObjCDeclSpec::DQ_PR_copy |
-                     ObjCDeclSpec::DQ_PR_retain)))
+                     ObjCDeclSpec::DQ_PR_retain |
+                     ObjCDeclSpec::DQ_PR_strong)))
     return true;
   
-  // Check for more than one of { assign, copy, retain }.
+  // Check for more than one of { assign, copy, retain, strong }.
   unsigned AssignCopyRetMask = Attributes & (ObjCDeclSpec::DQ_PR_assign |
+                                         ObjCDeclSpec::DQ_PR_unsafe_unretained |
                                              ObjCDeclSpec::DQ_PR_copy |
-                                             ObjCDeclSpec::DQ_PR_retain);
+                                             ObjCDeclSpec::DQ_PR_retain|
+                                             ObjCDeclSpec::DQ_PR_strong);
   if (AssignCopyRetMask &&
       AssignCopyRetMask != ObjCDeclSpec::DQ_PR_assign &&
+      AssignCopyRetMask != ObjCDeclSpec::DQ_PR_unsafe_unretained &&
       AssignCopyRetMask != ObjCDeclSpec::DQ_PR_copy &&
-      AssignCopyRetMask != ObjCDeclSpec::DQ_PR_retain)
+      AssignCopyRetMask != ObjCDeclSpec::DQ_PR_retain &&
+      AssignCopyRetMask != ObjCDeclSpec::DQ_PR_strong)
     return true;
   
   return false;
@@ -4157,10 +4207,15 @@
     Results.AddResult(CodeCompletionResult("readonly"));
   if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_assign))
     Results.AddResult(CodeCompletionResult("assign"));
+  if (!ObjCPropertyFlagConflicts(Attributes,
+                                 ObjCDeclSpec::DQ_PR_unsafe_unretained))
+    Results.AddResult(CodeCompletionResult("unsafe_unretained"));
   if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_readwrite))
     Results.AddResult(CodeCompletionResult("readwrite"));
   if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_retain))
     Results.AddResult(CodeCompletionResult("retain"));
+  if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_strong))
+    Results.AddResult(CodeCompletionResult("strong"));
   if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_copy))
     Results.AddResult(CodeCompletionResult("copy"));
   if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_nonatomic))
@@ -4522,6 +4577,7 @@
   if (Method->isInstanceMethod())
     return llvm::StringSwitch<ObjCInterfaceDecl *>(Id->getName())
       .Case("retain", IFace)
+      .Case("strong", IFace)
       .Case("autorelease", IFace)
       .Case("copy", IFace)
       .Case("copyWithZone", IFace)
@@ -6273,6 +6329,7 @@
   Results.EnterNewScope();
   PrintingPolicy Policy(Context.PrintingPolicy);
   Policy.AnonymousTagLocations = false;
+  Policy.SuppressStrongLifetime = true;
   for (KnownMethodsMap::iterator M = KnownMethods.begin(), 
                               MEnd = KnownMethods.end();
        M != MEnd; ++M) {
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index c7545cf..4476211 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1928,6 +1928,7 @@
   return false;
 }
 
+
 void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
                                 const ObjCMethodDecl *oldMethod) {
   // Merge the attributes.
@@ -3473,6 +3474,50 @@
   DD->setQualifierInfo(SS.getWithLocInContext(DD->getASTContext()));
 }
 
+bool Sema::inferObjCARCLifetime(ValueDecl *decl) {
+  QualType type = decl->getType();
+  Qualifiers::ObjCLifetime lifetime = type.getObjCLifetime();
+  if (lifetime == Qualifiers::OCL_Autoreleasing) {
+    // Various kinds of declaration aren't allowed to be __autoreleasing.
+    unsigned kind = -1U;
+    if (VarDecl *var = dyn_cast<VarDecl>(decl)) {
+      if (var->hasAttr<BlocksAttr>())
+        kind = 0; // __block
+      else if (!var->hasLocalStorage())
+        kind = 1; // global
+    } else if (isa<ObjCIvarDecl>(decl)) {
+      kind = 3; // ivar
+    } else if (isa<FieldDecl>(decl)) {
+      kind = 2; // field
+    }
+
+    if (kind != -1U) {
+      Diag(decl->getLocation(), diag::err_arc_autoreleasing_var)
+        << kind;
+    }
+  } else if (lifetime == Qualifiers::OCL_None) {
+    // Try to infer lifetime.
+    if (!type->isObjCLifetimeType())
+      return false;
+
+    lifetime = type->getObjCARCImplicitLifetime();
+    type = Context.getLifetimeQualifiedType(type, lifetime);
+    decl->setType(type);
+  }
+  
+  if (VarDecl *var = dyn_cast<VarDecl>(decl)) {
+    // Thread-local variables cannot have lifetime.
+    if (lifetime && lifetime != Qualifiers::OCL_ExplicitNone &&
+        var->isThreadSpecified()) {
+      Diag(var->getLocation(), diag::err_arc_thread_lifetime)
+        << var->getType();
+      return true;
+    }
+  }
+  
+  return false;
+}
+
 NamedDecl*
 Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
                               QualType R, TypeSourceInfo *TInfo,
@@ -3631,6 +3676,11 @@
   // Handle attributes prior to checking for duplicates in MergeVarDecl
   ProcessDeclAttributes(S, NewVD, D);
 
+  // In auto-retain/release, infer strong retension for variables of
+  // retainable type.
+  if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(NewVD))
+    NewVD->setInvalidDecl();
+
   // Handle GNU asm-label extension (encoded as an attribute).
   if (Expr *E = (Expr*)D.getAsmLabel()) {
     // The parser guarantees this is a string.
@@ -5229,6 +5279,10 @@
     VDecl->setTypeSourceInfo(DeducedType);
     VDecl->setType(DeducedType->getType());
 
+    // In ARC, infer lifetime.
+    if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(VDecl))
+      VDecl->setInvalidDecl();
+
     // If this is a redeclaration, check that the type we just deduced matches
     // the previously declared type.
     if (VarDecl *Old = VDecl->getPreviousDeclaration())
@@ -5471,7 +5525,10 @@
   
   // Check any implicit conversions within the expression.
   CheckImplicitConversions(Init, VDecl->getLocation());
-
+  
+  if (!VDecl->isInvalidDecl())
+    checkUnsafeAssigns(VDecl->getLocation(), VDecl->getType(), Init);
+  
   Init = MaybeCreateExprWithCleanups(Init);
   // Attach the initializer to the decl.
   VDecl->setInit(Init);
@@ -5740,6 +5797,23 @@
 void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
   if (var->isInvalidDecl()) return;
 
+  // In ARC, don't allow jumps past the implicit initialization of a
+  // local retaining variable.
+  if (getLangOptions().ObjCAutoRefCount &&
+      var->hasLocalStorage()) {
+    switch (var->getType().getObjCLifetime()) {
+    case Qualifiers::OCL_None:
+    case Qualifiers::OCL_ExplicitNone:
+    case Qualifiers::OCL_Autoreleasing:
+      break;
+
+    case Qualifiers::OCL_Weak:
+    case Qualifiers::OCL_Strong:
+      getCurFunction()->setHasBranchProtectedScope();
+      break;
+    }
+  }
+
   // All the following checks are C++ only.
   if (!getLangOptions().CPlusPlus) return;
 
@@ -6008,7 +6082,7 @@
 
   // Warn if the return value is pass-by-value and larger than the specified
   // threshold.
-  if (ReturnTy->isPODType()) {
+  if (ReturnTy.isPODType(Context)) {
     unsigned Size = Context.getTypeSizeInChars(ReturnTy).getQuantity();
     if (Size > LangOpts.NumLargeByValueCopy)
       Diag(D->getLocation(), diag::warn_return_value_size)
@@ -6019,7 +6093,7 @@
   // threshold.
   for (; Param != ParamEnd; ++Param) {
     QualType T = (*Param)->getType();
-    if (!T->isPODType())
+    if (!T.isPODType(Context))
       continue;
     unsigned Size = Context.getTypeSizeInChars(T).getQuantity();
     if (Size > LangOpts.NumLargeByValueCopy)
@@ -6033,6 +6107,28 @@
                                   QualType T, TypeSourceInfo *TSInfo,
                                   VarDecl::StorageClass StorageClass,
                                   VarDecl::StorageClass StorageClassAsWritten) {
+  // In ARC, infer a lifetime qualifier for appropriate parameter types.
+  if (getLangOptions().ObjCAutoRefCount &&
+      T.getObjCLifetime() == Qualifiers::OCL_None &&
+      T->isObjCLifetimeType()) {
+
+    Qualifiers::ObjCLifetime lifetime;
+
+    // Special cases for arrays:
+    //   - if it's const, use __unsafe_unretained
+    //   - otherwise, it's an error
+    if (T->isArrayType()) {
+      if (!T.isConstQualified()) {
+        Diag(NameLoc, diag::err_arc_array_param_no_lifetime)
+          << TSInfo->getTypeLoc().getSourceRange();
+      }
+      lifetime = Qualifiers::OCL_ExplicitNone;
+    } else {
+      lifetime = T->getObjCARCImplicitLifetime();
+    }
+    T = Context.getLifetimeQualifiedType(T, lifetime);
+  }
+
   ParmVarDecl *New = ParmVarDecl::Create(Context, DC, StartLoc, NameLoc, Name,
                                          adjustParameterType(T), TSInfo,
                                          StorageClass, StorageClassAsWritten,
@@ -6369,7 +6465,7 @@
     // Verify that that gotos and switch cases don't jump into scopes illegally.
     if (getCurFunction()->NeedsScopeChecking() &&
         !dcl->isInvalidDecl() &&
-        !hasAnyErrorsInThisFunction())
+        !hasAnyUnrecoverableErrorsInThisFunction())
       DiagnoseInvalidJumps(Body);
 
     if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl)) {
@@ -6384,15 +6480,17 @@
     // been leftover. This ensures that these temporaries won't be picked up for
     // deletion in some later function.
     if (PP.getDiagnostics().hasErrorOccurred() ||
-        PP.getDiagnostics().getSuppressAllDiagnostics())
+        PP.getDiagnostics().getSuppressAllDiagnostics()) {
       ExprTemporaries.clear();
-    else if (!isa<FunctionTemplateDecl>(dcl)) {
+      ExprNeedsCleanups = false;
+    } else if (!isa<FunctionTemplateDecl>(dcl)) {
       // Since the body is valid, issue any analysis-based warnings that are
       // enabled.
       ActivePolicy = &WP;
     }
 
     assert(ExprTemporaries.empty() && "Leftover temporaries in function");
+    assert(!ExprNeedsCleanups && "Unaccounted cleanups in function");
   }
   
   if (!IsInstantiation)
@@ -6403,8 +6501,10 @@
   // If any errors have occurred, clear out any temporaries that may have
   // been leftover. This ensures that these temporaries won't be picked up for
   // deletion in some later function.
-  if (getDiagnostics().hasErrorOccurred())
+  if (getDiagnostics().hasErrorOccurred()) {
     ExprTemporaries.clear();
+    ExprNeedsCleanups = false;
+  }
 
   return dcl;
 }
@@ -7736,6 +7836,11 @@
     // FIXME: What to pass instead of TUScope?
     ProcessDeclAttributes(TUScope, NewFD, *D);
 
+  // In auto-retain/release, infer strong retension for fields of
+  // retainable type.
+  if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(NewFD))
+    NewFD->setInvalidDecl();
+
   if (T.isObjCGCWeak())
     Diag(Loc, diag::warn_attribute_weak_on_field);
 
@@ -7769,6 +7874,21 @@
         member = CXXDestructor;
 
       if (member != CXXInvalid) {
+        if (getLangOptions().ObjCAutoRefCount && RDecl->hasObjectMember()) {
+          // Objective-C++ ARC: it is an error to have a non-trivial field of
+          // a union. However, system headers in Objective-C programs 
+          // occasionally have Objective-C lifetime objects within unions,
+          // and rather than cause the program to fail, we make those 
+          // members unavailable.
+          SourceLocation Loc = FD->getLocation();
+          if (getSourceManager().isInSystemHeader(Loc)) {
+            if (!FD->hasAttr<UnavailableAttr>())
+              FD->addAttr(new (Context) UnavailableAttr(Loc, Context,
+                                  "this system field has retaining lifetime"));
+            return false;
+          }
+        }
+        
         Diag(FD->getLocation(), diag::err_illegal_union_or_anon_struct_member)
               << (int)FD->getParent()->isUnion() << FD->getDeclName() << member;
         DiagnoseNontrivial(RT, member);
@@ -7921,6 +8041,21 @@
         return;
       }
     }
+    
+    if (EltTy->isObjCLifetimeType()) {
+      switch (EltTy.getObjCLifetime()) {
+      case Qualifiers::OCL_None:
+      case Qualifiers::OCL_ExplicitNone:
+        break;
+          
+      case Qualifiers::OCL_Autoreleasing:
+      case Qualifiers::OCL_Weak:
+      case Qualifiers::OCL_Strong:
+        Diag((*fi)->getLocation(), diag::note_nontrivial_objc_lifetime)
+          << QT << EltTy.getObjCLifetime();
+        return;
+      }
+    }
   }
 
   assert(0 && "found no explanation for non-trivial member");
@@ -8030,6 +8165,10 @@
   if (D.isInvalidType())
     NewID->setInvalidDecl();
 
+  // In ARC, infer 'retaining' for ivars of retainable type.
+  if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(NewID))
+    NewID->setInvalidDecl();
+
   if (II) {
     // FIXME: When interfaces are DeclContexts, we'll need to add
     // these to the interface.
@@ -8101,6 +8240,7 @@
   llvm::SmallVector<FieldDecl*, 32> RecFields;
 
   RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl);
+  bool ARCErrReported = false;
   for (unsigned i = 0; i != NumFields; ++i) {
     FieldDecl *FD = cast<FieldDecl>(Fields[i]);
 
@@ -8166,7 +8306,7 @@
         continue;
       }
       if (!FD->getType()->isDependentType() &&
-          !Context.getBaseElementType(FD->getType())->isPODType()) {
+          !Context.getBaseElementType(FD->getType()).isPODType(Context)) {
         Diag(FD->getLocation(), diag::err_flexible_array_has_nonpod_type)
           << FD->getDeclName() << FD->getType();
         FD->setInvalidDecl();
@@ -8213,17 +8353,45 @@
       FD->setInvalidDecl();
       EnclosingDecl->setInvalidDecl();
       continue;
-    } else if (getLangOptions().ObjC1 &&
+    } 
+    else if (!getLangOptions().CPlusPlus) {
+      if (getLangOptions().ObjCAutoRefCount && Record && !ARCErrReported) {
+        // It's an error in ARC if a field has lifetime.
+        // We don't want to report this in a system header, though,
+        // so we just make the field unavailable.
+        // FIXME: that's really not sufficient; we need to make the type
+        // itself invalid to, say, initialize or copy.
+        QualType T = FD->getType();
+        Qualifiers::ObjCLifetime lifetime = T.getObjCLifetime();
+        if (lifetime && lifetime != Qualifiers::OCL_ExplicitNone) {
+          SourceLocation loc = FD->getLocation();
+          if (getSourceManager().isInSystemHeader(loc)) {
+            if (!FD->hasAttr<UnavailableAttr>()) {
+              FD->addAttr(new (Context) UnavailableAttr(loc, Context,
+                                "this system field has retaining lifetime"));
+            }
+          } else {
+            Diag(FD->getLocation(), diag::err_arc_objc_object_in_struct);
+          }
+          ARCErrReported = true;
+        }
+      }
+      else if (getLangOptions().ObjC1 &&
                getLangOptions().getGCMode() != LangOptions::NonGC &&
-               Record &&
-               (FD->getType()->isObjCObjectPointerType() ||
-                FD->getType().isObjCGCStrong()))
-      Record->setHasObjectMember(true);
-    else if (Context.getAsArrayType(FD->getType())) {
-      QualType BaseType = Context.getBaseElementType(FD->getType());
-      if (Record && BaseType->isRecordType() && 
-          BaseType->getAs<RecordType>()->getDecl()->hasObjectMember())
-        Record->setHasObjectMember(true);
+               Record && !Record->hasObjectMember()) {
+        if (FD->getType()->isObjCObjectPointerType() ||
+            FD->getType().isObjCGCStrong())
+          Record->setHasObjectMember(true);
+        else if (Context.getAsArrayType(FD->getType())) {
+          QualType BaseType = Context.getBaseElementType(FD->getType());
+          if (BaseType->isRecordType() && 
+              BaseType->getAs<RecordType>()->getDecl()->hasObjectMember())
+            Record->setHasObjectMember(true);
+          else if (BaseType->isObjCObjectPointerType() ||
+                   BaseType.isObjCGCStrong())
+                 Record->setHasObjectMember(true);
+        }
+      }
     }
     // Keep track of the number of named members.
     if (FD->getIdentifier())
@@ -8242,6 +8410,42 @@
           Convs->setAccess(I, (*I)->getAccess());
         
         if (!CXXRecord->isDependentType()) {
+          // Objective-C Automatic Reference Counting:
+          //   If a class has a non-static data member of Objective-C pointer
+          //   type (or array thereof), it is a non-POD type and its
+          //   default constructor (if any), copy constructor, copy assignment
+          //   operator, and destructor are non-trivial.
+          //
+          // This rule is also handled by CXXRecordDecl::completeDefinition(). 
+          // However, here we check whether this particular class is only 
+          // non-POD because of the presence of an Objective-C pointer member. 
+          // If so, objects of this type cannot be shared between code compiled 
+          // with instant objects and code compiled with manual retain/release.
+          if (getLangOptions().ObjCAutoRefCount &&
+              CXXRecord->hasObjectMember() && 
+              CXXRecord->getLinkage() == ExternalLinkage) {
+            if (CXXRecord->isPOD()) {
+              Diag(CXXRecord->getLocation(), 
+                   diag::warn_arc_non_pod_class_with_object_member)
+               << CXXRecord;
+            } else {
+              // FIXME: Fix-Its would be nice here, but finding a good location
+              // for them is going to be tricky.
+              if (CXXRecord->hasTrivialCopyConstructor())
+                Diag(CXXRecord->getLocation(), 
+                     diag::warn_arc_trivial_member_function_with_object_member)
+                  << CXXRecord << 0;
+              if (CXXRecord->hasTrivialCopyAssignment())
+                Diag(CXXRecord->getLocation(), 
+                     diag::warn_arc_trivial_member_function_with_object_member)
+                << CXXRecord << 1;
+              if (CXXRecord->hasTrivialDestructor())
+                Diag(CXXRecord->getLocation(), 
+                     diag::warn_arc_trivial_member_function_with_object_member)
+                << CXXRecord << 2;
+            }
+          }
+          
           // Adjust user-defined destructor exception spec.
           if (getLangOptions().CPlusPlus0x &&
               CXXRecord->hasUserDeclaredDestructor())
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 430b4f9..4769b09 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -17,6 +17,7 @@
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/Expr.h"
+#include "clang/Basic/SourceManager.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Sema/DeclSpec.h"
 #include "clang/Sema/DelayedDiagnostic.h"
@@ -101,8 +102,9 @@
 /// Return true if the given decl has a declarator that should have
 /// been processed by Sema::GetTypeForDeclarator.
 static bool hasDeclarator(const Decl *d) {
-  // In some sense, TypedefNameDecl really *ought* to be a DeclaratorDecl.
-  return isa<DeclaratorDecl>(d) || isa<BlockDecl>(d) || isa<TypedefNameDecl>(d);
+  // In some sense, TypedefDecl really *ought* to be a DeclaratorDecl.
+  return isa<DeclaratorDecl>(d) || isa<BlockDecl>(d) || isa<TypedefNameDecl>(d) ||
+         isa<ObjCPropertyDecl>(d);
 }
 
 /// hasFunctionProto - Return true if the given decl has a argument
@@ -1216,8 +1218,16 @@
     return;
   }
 
-  decl->addAttr(new (S.Context) ObjCMethodFamilyAttr(attr.getLoc(),
-                                                     S.Context, family));
+  if (family == ObjCMethodFamilyAttr::OMF_init && 
+      !method->getResultType()->isObjCObjectPointerType()) {
+    S.Diag(method->getLocation(), diag::err_init_method_bad_return_type)
+      << method->getResultType();
+    // Ignore the attribute.
+    return;
+  }
+
+  method->addAttr(new (S.Context) ObjCMethodFamilyAttr(attr.getLoc(),
+                                                       S.Context, family));
 }
 
 static void HandleObjCExceptionAttr(Decl *D, const AttributeList &Attr,
@@ -2706,6 +2716,9 @@
 
   if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d))
     returnType = MD->getResultType();
+  else if (S.getLangOptions().ObjCAutoRefCount && hasDeclarator(d) &&
+           (attr.getKind() == AttributeList::AT_ns_returns_retained))
+    return; // ignore: was handled as a type attribute
   else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d))
     returnType = FD->getResultType();
   else {
@@ -2767,6 +2780,62 @@
   };
 }
 
+static void HandleObjCLifetimeAttr(Decl *d, const AttributeList &attr,
+                                   Sema &S) {
+  if (hasDeclarator(d)) return;
+
+  SourceLocation L = attr.getLoc();
+  S.Diag(d->getLocStart(), diag::err_attribute_wrong_decl_type)
+    << SourceRange(L, L) << attr.getName() << 12 /* variable */;
+}
+
+static void HandleObjCPreciseLifetimeAttr(Decl *d, const AttributeList &attr,
+                                          Sema &S) {
+  if (!isa<VarDecl>(d) && !isa<FieldDecl>(d)) {
+    SourceLocation L = attr.getLoc();
+    S.Diag(d->getLocStart(), diag::err_attribute_wrong_decl_type)
+      << SourceRange(L, L) << attr.getName() << 12 /* variable */;
+    return;
+  }
+
+  ValueDecl *vd = cast<ValueDecl>(d);
+  QualType type = vd->getType();
+
+  if (!type->isDependentType() &&
+      !type->isObjCLifetimeType()) {
+    S.Diag(attr.getLoc(), diag::err_objc_precise_lifetime_bad_type)
+      << type;
+    return;
+  }
+
+  Qualifiers::ObjCLifetime lifetime = type.getObjCLifetime();
+
+  // If we have no lifetime yet, check the lifetime we're presumably
+  // going to infer.
+  if (lifetime == Qualifiers::OCL_None && !type->isDependentType())
+    lifetime = type->getObjCARCImplicitLifetime();
+
+  switch (lifetime) {
+  case Qualifiers::OCL_None:
+    assert(type->isDependentType() &&
+           "didn't infer lifetime for non-dependent type?");
+    break;
+
+  case Qualifiers::OCL_Weak:   // meaningful
+  case Qualifiers::OCL_Strong: // meaningful
+    break;
+
+  case Qualifiers::OCL_ExplicitNone:
+  case Qualifiers::OCL_Autoreleasing:
+    S.Diag(attr.getLoc(), diag::warn_objc_precise_lifetime_meaningless)
+      << (lifetime == Qualifiers::OCL_Autoreleasing);
+    break;
+  }
+
+  d->addAttr(::new (S.Context)
+                 ObjCPreciseLifetimeAttr(attr.getLoc(), S.Context));
+}
+
 static bool isKnownDeclSpecAttr(const AttributeList &Attr) {
   return Attr.getKind() == AttributeList::AT_dllimport ||
          Attr.getKind() == AttributeList::AT_dllexport ||
@@ -2909,6 +2978,11 @@
   case AttributeList::AT_shared:      HandleSharedAttr      (D, Attr, S); break;
   case AttributeList::AT_vecreturn:   HandleVecReturnAttr   (D, Attr, S); break;
 
+  case AttributeList::AT_objc_lifetime:
+    HandleObjCLifetimeAttr(D, Attr, S); break;
+  case AttributeList::AT_objc_precise_lifetime:
+    HandleObjCPreciseLifetimeAttr(D, Attr, S); break;
+
   // Checker-specific.
   case AttributeList::AT_cf_consumed:
   case AttributeList::AT_ns_consumed: HandleNSConsumedAttr  (D, Attr, S); break;
@@ -3117,6 +3191,32 @@
     ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable);
 }
 
+/// Is the given declaration allowed to use a forbidden type?
+static bool isForbiddenTypeAllowed(Sema &S, Decl *decl) {
+  // Private ivars are always okay.  Unfortunately, people don't
+  // always properly make their ivars private, even in system headers.
+  // Plus we need to make fields okay, too.
+  if (!isa<FieldDecl>(decl) && !isa<ObjCPropertyDecl>(decl))
+    return false;
+
+  // Require it to be declared in a system header.
+  return S.Context.getSourceManager().isInSystemHeader(decl->getLocation());
+}
+
+/// Handle a delayed forbidden-type diagnostic.
+static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag,
+                                       Decl *decl) {
+  if (decl && isForbiddenTypeAllowed(S, decl)) {
+    decl->addAttr(new (S.Context) UnavailableAttr(diag.Loc, S.Context,
+                        "this system declaration uses an unsupported type"));
+    return;
+  }
+
+  S.Diag(diag.Loc, diag.getForbiddenTypeDiagnostic())
+    << diag.getForbiddenTypeOperand() << diag.getForbiddenTypeArgument();
+  diag.Triggered = true;
+}
+
 // This duplicates a vector push_back but hides the need to know the
 // size of the type.
 void Sema::DelayedDiagnostics::add(const DelayedDiagnostic &diag) {
@@ -3179,6 +3279,10 @@
       case DelayedDiagnostic::Access:
         S.HandleDelayedAccessCheck(diag, decl);
         break;
+
+      case DelayedDiagnostic::ForbiddenType:
+        handleDelayedForbiddenType(S, diag, decl);
+        break;
       }
     }
   }
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index ce99efb..09597d2 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -762,13 +762,6 @@
     QualType NewBaseType
       = Context.getCanonicalType(Bases[idx]->getType());
     NewBaseType = NewBaseType.getLocalUnqualifiedType();
-    if (!Class->hasObjectMember()) {
-      if (const RecordType *FDTTy = 
-            NewBaseType.getTypePtr()->getAs<RecordType>())
-        if (FDTTy->getDecl()->hasObjectMember())
-          Class->setHasObjectMember(true);
-    }
-    
     if (KnownBaseTypes[NewBaseType]) {
       // C++ [class.mi]p3:
       //   A class shall not be specified as a direct base class of a
@@ -1619,12 +1612,7 @@
     Init = new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
                                        RParenLoc);
 
-    // Erase any temporaries within this evaluation context; we're not
-    // going to track them in the AST, since we'll be rebuilding the
-    // ASTs during template instantiation.
-    ExprTemporaries.erase(
-              ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries,
-                          ExprTemporaries.end());
+    DiscardCleanupsInEvaluationContext();
   } else {
     // Initialize the member.
     InitializedEntity MemberEntity =
@@ -1817,12 +1805,7 @@
       = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs,
                                           RParenLoc));
 
-    // Erase any temporaries within this evaluation context; we're not
-    // going to track them in the AST, since we'll be rebuilding the
-    // ASTs during template instantiation.
-    ExprTemporaries.erase(
-              ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries,
-                          ExprTemporaries.end());
+    DiscardCleanupsInEvaluationContext();
 
     return new (Context) CXXCtorInitializer(Context, BaseTInfo, 
                                                     /*IsVirtual=*/false,
@@ -2134,6 +2117,20 @@
     }
   }
   
+  if (SemaRef.getLangOptions().ObjCAutoRefCount &&
+      FieldBaseElementType->isObjCRetainableType() &&
+      FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_None &&
+      FieldBaseElementType.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) {
+    // Instant objects:
+    //   Default-initialize Objective-C pointers to NULL.
+    CXXMemberInit
+      = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field, 
+                                                 Loc, Loc, 
+                 new (SemaRef.Context) ImplicitValueInitExpr(Field->getType()), 
+                                                 Loc);
+    return false;
+  }
+      
   // Nothing to initialize.
   CXXMemberInit = 0;
   return false;
@@ -7041,10 +7038,8 @@
     // explicit assignments, do so. This optimization only applies for arrays 
     // of scalars and arrays of class type with trivial copy-assignment 
     // operators.
-    if (FieldType->isArrayType() &&
-        (!BaseType->isRecordType() || 
-         cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl())
-           ->hasTrivialCopyAssignment())) {
+    if (FieldType->isArrayType() && 
+        BaseType.hasTrivialCopyAssignment(Context)) {
       // Compute the size of the memory buffer to be copied.
       QualType SizeType = Context.getSizeType();
       llvm::APInt Size(Context.getTypeSize(SizeType), 
@@ -7523,6 +7518,10 @@
     VDecl->setTypeSourceInfo(DeducedType);
     VDecl->setType(DeducedType->getType());
 
+    // In ARC, infer lifetime.
+    if (getLangOptions().ObjCAutoRefCount && inferObjCARCLifetime(VDecl))
+      VDecl->setInvalidDecl();
+
     // If this is a redeclaration, check that the type we just deduced matches
     // the previously declared type.
     if (VarDecl *Old = VDecl->getPreviousDeclaration())
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index bfa2ef4..563de6f 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -16,14 +16,96 @@
 #include "clang/Sema/ExternalSemaSource.h"
 #include "clang/Sema/Scope.h"
 #include "clang/Sema/ScopeInfo.h"
+#include "clang/AST/ASTConsumer.h"
 #include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceManager.h"
 #include "clang/Sema/DeclSpec.h"
 #include "llvm/ADT/DenseSet.h"
 
 using namespace clang;
 
+/// Check whether the given method, which must be in the 'init'
+/// family, is a valid member of that family.
+///
+/// \param receiverTypeIfCall - if null, check this as if declaring it;
+///   if non-null, check this as if making a call to it with the given
+///   receiver type
+///
+/// \return true to indicate that there was an error and appropriate
+///   actions were taken
+bool Sema::checkInitMethod(ObjCMethodDecl *method,
+                           QualType receiverTypeIfCall) {
+  if (method->isInvalidDecl()) return true;
+
+  // This castAs is safe: methods that don't return an object
+  // pointer won't be inferred as inits and will reject an explicit
+  // objc_method_family(init).
+
+  // We ignore protocols here.  Should we?  What about Class?
+
+  const ObjCObjectType *result = method->getResultType()
+    ->castAs<ObjCObjectPointerType>()->getObjectType();
+
+  if (result->isObjCId()) {
+    return false;
+  } else if (result->isObjCClass()) {
+    // fall through: always an error
+  } else {
+    ObjCInterfaceDecl *resultClass = result->getInterface();
+    assert(resultClass && "unexpected object type!");
+
+    // It's okay for the result type to still be a forward declaration
+    // if we're checking an interface declaration.
+    if (resultClass->isForwardDecl()) {
+      if (receiverTypeIfCall.isNull() &&
+          !isa<ObjCImplementationDecl>(method->getDeclContext()))
+        return false;
+
+    // Otherwise, we try to compare class types.
+    } else {
+      // If this method was declared in a protocol, we can't check
+      // anything unless we have a receiver type that's an interface.
+      const ObjCInterfaceDecl *receiverClass = 0;
+      if (isa<ObjCProtocolDecl>(method->getDeclContext())) {
+        if (receiverTypeIfCall.isNull())
+          return false;
+
+        receiverClass = receiverTypeIfCall->castAs<ObjCObjectPointerType>()
+          ->getInterfaceDecl();
+
+        // This can be null for calls to e.g. id<Foo>.
+        if (!receiverClass) return false;
+      } else {
+        receiverClass = method->getClassInterface();
+        assert(receiverClass && "method not associated with a class!");
+      }
+
+      // If either class is a subclass of the other, it's fine.
+      if (receiverClass->isSuperClassOf(resultClass) ||
+          resultClass->isSuperClassOf(receiverClass))
+        return false;
+    }
+  }
+
+  SourceLocation loc = method->getLocation();
+
+  // If we're in a system header, and this is not a call, just make
+  // the method unusable.
+  if (receiverTypeIfCall.isNull() && getSourceManager().isInSystemHeader(loc)) {
+    method->addAttr(new (Context) UnavailableAttr(loc, Context,
+                "init method returns a type unrelated to its receiver type"));
+    return true;
+  }
+
+  // Otherwise, it's an error.
+  Diag(loc, diag::err_arc_init_method_unrelated_result_type);
+  method->setInvalidDecl();
+  return true;
+}
+
 bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, 
                                    const ObjCMethodDecl *Overridden,
                                    bool IsImplementation) {
@@ -36,7 +118,7 @@
     QualType ResultType = NewMethod->getResultType();
     SourceRange ResultTypeRange;
     if (const TypeSourceInfo *ResultTypeInfo 
-        = NewMethod->getResultTypeSourceInfo())
+                                        = NewMethod->getResultTypeSourceInfo())
       ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange();
     
     // Figure out which class this method is part of, if any.
@@ -107,10 +189,10 @@
       if (CheckObjCMethodOverrides(S, NewMethod, Category, false))
         return true;
     }
-    
+
     // Look through protocols.
     for (ObjCList<ObjCProtocolDecl>::iterator I = Class->protocol_begin(),
-         IEnd = Class->protocol_end();
+                                           IEnd = Class->protocol_end();
          I != IEnd; ++I)
       if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
         return true;
@@ -123,7 +205,7 @@
   if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC)) {
     // Look through protocols.
     for (ObjCList<ObjCProtocolDecl>::iterator I = Category->protocol_begin(),
-         IEnd = Category->protocol_end();
+                                           IEnd = Category->protocol_end();
          I != IEnd; ++I)
       if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
         return true;
@@ -134,7 +216,7 @@
   if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC)) {
     // Look through protocols.
     for (ObjCList<ObjCProtocolDecl>::iterator I = Protocol->protocol_begin(),
-         IEnd = Protocol->protocol_end();
+                                           IEnd = Protocol->protocol_end();
          I != IEnd; ++I)
       if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
         return true;
@@ -149,13 +231,13 @@
                                     DeclContext *DC) {
   if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(DC))
     return ::CheckObjCMethodOverrides(*this, NewMethod, Class);
-  
+
   if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC))
     return ::CheckObjCMethodOverrides(*this, NewMethod, Category);
-  
+
   if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC))
     return ::CheckObjCMethodOverrides(*this, NewMethod, Protocol);
-  
+
   if (ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(DC))
     return ::CheckObjCMethodOverrides(*this, NewMethod, 
                                       Impl->getClassInterface());
@@ -167,6 +249,50 @@
   return ::CheckObjCMethodOverrides(*this, NewMethod, CurContext);
 }
 
+/// \brief Check a method declaration for compatibility with the Objective-C
+/// ARC conventions.
+static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) {
+  ObjCMethodFamily family = method->getMethodFamily();
+  switch (family) {
+  case OMF_None:
+  case OMF_dealloc:
+  case OMF_retain:
+  case OMF_release:
+  case OMF_autorelease:
+  case OMF_retainCount:
+  case OMF_self:
+    return false;
+
+  case OMF_init:
+    // If the method doesn't obey the init rules, don't bother annotating it.
+    if (S.checkInitMethod(method, QualType()))
+      return true;
+
+    method->addAttr(new (S.Context) NSConsumesSelfAttr(SourceLocation(),
+                                                       S.Context));
+
+    // Don't add a second copy of this attribute, but otherwise don't
+    // let it be suppressed.
+    if (method->hasAttr<NSReturnsRetainedAttr>())
+      return false;
+    break;
+
+  case OMF_alloc:
+  case OMF_copy:
+  case OMF_mutableCopy:
+  case OMF_new:
+    if (method->hasAttr<NSReturnsRetainedAttr>() ||
+        method->hasAttr<NSReturnsNotRetainedAttr>() ||
+        method->hasAttr<NSReturnsAutoreleasedAttr>())
+      return false;
+    break;
+  }
+
+  method->addAttr(new (S.Context) NSReturnsRetainedAttr(SourceLocation(),
+                                                        S.Context));
+  return false;
+}
+
 static void DiagnoseObjCImplementedDeprecations(Sema &S,
                                                 NamedDecl *ND,
                                                 SourceLocation ImplLoc,
@@ -220,6 +346,30 @@
     if ((*PI)->getIdentifier())
       PushOnScopeChains(*PI, FnBodyScope);
   }
+
+  // In ARC, disallow definition of retain/release/autorelease/retainCount
+  if (getLangOptions().ObjCAutoRefCount) {
+    switch (MDecl->getMethodFamily()) {
+    case OMF_retain:
+    case OMF_retainCount:
+    case OMF_release:
+    case OMF_autorelease:
+      Diag(MDecl->getLocation(), diag::err_arc_illegal_method_def)
+        << MDecl->getSelector();
+      break;
+
+    case OMF_None:
+    case OMF_dealloc:
+    case OMF_alloc:
+    case OMF_init:
+    case OMF_mutableCopy:
+    case OMF_copy:
+    case OMF_new:
+    case OMF_self:
+      break;
+    }
+  }
+
   // Warn on implementating deprecated methods under 
   // -Wdeprecated-implementations flag.
   if (ObjCInterfaceDecl *IC = MDecl->getClassInterface())
@@ -1099,11 +1249,83 @@
   S.Diag(IfaceVar->getLocation(), diag::note_previous_definition)
     << getTypeRange(IfaceVar->getTypeSourceInfo());
 }
-                                     
+
+/// In ARC, check whether the conventional meanings of the two methods
+/// match.  If they don't, it's a hard error.
+static bool checkMethodFamilyMismatch(Sema &S, ObjCMethodDecl *impl,
+                                      ObjCMethodDecl *decl) {
+  ObjCMethodFamily implFamily = impl->getMethodFamily();
+  ObjCMethodFamily declFamily = decl->getMethodFamily();
+  if (implFamily == declFamily) return false;
+
+  // Since conventions are sorted by selector, the only possibility is
+  // that the types differ enough to cause one selector or the other
+  // to fall out of the family.
+  assert(implFamily == OMF_None || declFamily == OMF_None);
+
+  // No further diagnostics required on invalid declarations.
+  if (impl->isInvalidDecl() || decl->isInvalidDecl()) return true;
+
+  const ObjCMethodDecl *unmatched = impl;
+  ObjCMethodFamily family = declFamily;
+  unsigned errorID = diag::err_arc_lost_method_convention;
+  unsigned noteID = diag::note_arc_lost_method_convention;
+  if (declFamily == OMF_None) {
+    unmatched = decl;
+    family = implFamily;
+    errorID = diag::err_arc_gained_method_convention;
+    noteID = diag::note_arc_gained_method_convention;
+  }
+
+  // Indexes into a %select clause in the diagnostic.
+  enum FamilySelector {
+    F_alloc, F_copy, F_mutableCopy = F_copy, F_init, F_new
+  };
+  FamilySelector familySelector = FamilySelector();
+
+  switch (family) {
+  case OMF_None: llvm_unreachable("logic error, no method convention");
+  case OMF_retain:
+  case OMF_release:
+  case OMF_autorelease:
+  case OMF_dealloc:
+  case OMF_retainCount:
+  case OMF_self:
+    // Mismatches for these methods don't change ownership
+    // conventions, so we don't care.
+    return false;
+
+  case OMF_init: familySelector = F_init; break;
+  case OMF_alloc: familySelector = F_alloc; break;
+  case OMF_copy: familySelector = F_copy; break;
+  case OMF_mutableCopy: familySelector = F_mutableCopy; break;
+  case OMF_new: familySelector = F_new; break;
+  }
+
+  enum ReasonSelector { R_NonObjectReturn, R_UnrelatedReturn };
+  ReasonSelector reasonSelector;
+
+  // The only reason these methods don't fall within their families is
+  // due to unusual result types.
+  if (unmatched->getResultType()->isObjCObjectPointerType()) {
+    reasonSelector = R_UnrelatedReturn;
+  } else {
+    reasonSelector = R_NonObjectReturn;
+  }
+
+  S.Diag(impl->getLocation(), errorID) << familySelector << reasonSelector;
+  S.Diag(decl->getLocation(), noteID) << familySelector << reasonSelector;
+
+  return true;
+}
 
 void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl,
                                        ObjCMethodDecl *MethodDecl,
                                        bool IsProtocolMethodDecl) {
+  if (getLangOptions().ObjCAutoRefCount &&
+      checkMethodFamilyMismatch(*this, ImpMethodDecl, MethodDecl))
+    return;
+
   CheckMethodOverrideReturn(*this, ImpMethodDecl, MethodDecl, 
                             IsProtocolMethodDecl);
 
@@ -1430,48 +1652,82 @@
   return CDecl;
 }
 
+static bool matchTypes(ASTContext &Context, Sema::MethodMatchStrategy strategy,
+                       QualType leftQT, QualType rightQT) {
+  const Type *left =
+    Context.getCanonicalType(leftQT).getUnqualifiedType().getTypePtr();
+  const Type *right =
+    Context.getCanonicalType(rightQT).getUnqualifiedType().getTypePtr();
+
+  if (left == right) return true;
+
+  // If we're doing a strict match, the types have to match exactly.
+  if (strategy == Sema::MMS_strict) return false;
+
+  if (left->isIncompleteType() || right->isIncompleteType()) return false;
+
+  // Otherwise, use this absurdly complicated algorithm to try to
+  // validate the basic, low-level compatibility of the two types.
+
+  // As a minimum, require the sizes and alignments to match.
+  if (Context.getTypeInfo(left) != Context.getTypeInfo(right))
+    return false;
+
+  // Consider all the kinds of non-dependent canonical types:
+  // - functions and arrays aren't possible as return and parameter types
+  
+  // - vector types of equal size can be arbitrarily mixed
+  if (isa<VectorType>(left)) return isa<VectorType>(right);
+  if (isa<VectorType>(right)) return false;
+
+  // - references should only match references of identical type
+  // - structs, unions, and Objective-C objects must match exactly
+  // - everything else should be a scalar
+  if (!left->isScalarType() || !right->isScalarType())
+    return false;
+
+  // Make scalars agree in kind, except count bools as chars.
+  Type::ScalarTypeKind leftSK = left->getScalarTypeKind();
+  Type::ScalarTypeKind rightSK = right->getScalarTypeKind();
+  if (leftSK == Type::STK_Bool) leftSK = Type::STK_Integral;
+  if (rightSK == Type::STK_Bool) rightSK = Type::STK_Integral;
+
+  // Note that data member pointers and function member pointers don't
+  // intermix because of the size differences.
+
+  return (leftSK == rightSK);
+}
 
 /// MatchTwoMethodDeclarations - Checks that two methods have matching type and
 /// returns true, or false, accordingly.
 /// TODO: Handle protocol list; such as id<p1,p2> in type comparisons
-bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *Method,
-                                      const ObjCMethodDecl *PrevMethod,
-                                      bool matchBasedOnSizeAndAlignment,
-                                      bool matchBasedOnStrictEqulity) {
-  QualType T1 = Context.getCanonicalType(Method->getResultType());
-  QualType T2 = Context.getCanonicalType(PrevMethod->getResultType());
+bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left,
+                                      const ObjCMethodDecl *right,
+                                      MethodMatchStrategy strategy) {
+  if (!matchTypes(Context, strategy,
+                  left->getResultType(), right->getResultType()))
+    return false;
 
-  if (T1 != T2) {
-    // The result types are different.
-    if (!matchBasedOnSizeAndAlignment || matchBasedOnStrictEqulity)
-      return false;
-    // Incomplete types don't have a size and alignment.
-    if (T1->isIncompleteType() || T2->isIncompleteType())
-      return false;
-    // Check is based on size and alignment.
-    if (Context.getTypeInfo(T1) != Context.getTypeInfo(T2))
-      return false;
-  }
+  if (getLangOptions().ObjCAutoRefCount &&
+      (left->hasAttr<NSReturnsRetainedAttr>()
+         != right->hasAttr<NSReturnsRetainedAttr>() ||
+       left->hasAttr<NSConsumesSelfAttr>()
+         != right->hasAttr<NSConsumesSelfAttr>()))
+    return false;
 
-  ObjCMethodDecl::param_iterator ParamI = Method->param_begin(),
-       E = Method->param_end();
-  ObjCMethodDecl::param_iterator PrevI = PrevMethod->param_begin();
+  ObjCMethodDecl::param_iterator
+    li = left->param_begin(), le = left->param_end(), ri = right->param_begin();
 
-  for (; ParamI != E; ++ParamI, ++PrevI) {
-    assert(PrevI != PrevMethod->param_end() && "Param mismatch");
-    T1 = Context.getCanonicalType((*ParamI)->getType());
-    T2 = Context.getCanonicalType((*PrevI)->getType());
-    if (T1 != T2) {
-      // The result types are different.
-      if (!matchBasedOnSizeAndAlignment || matchBasedOnStrictEqulity)
-        return false;
-      // Incomplete types don't have a size and alignment.
-      if (T1->isIncompleteType() || T2->isIncompleteType())
-        return false;
-      // Check is based on size and alignment.
-      if (Context.getTypeInfo(T1) != Context.getTypeInfo(T2))
-        return false;
-    }
+  for (; li != le; ++li, ++ri) {
+    assert(ri != right->param_end() && "Param mismatch");
+    ParmVarDecl *lparm = *li, *rparm = *ri;
+
+    if (!matchTypes(Context, strategy, lparm->getType(), rparm->getType()))
+      return false;
+
+    if (getLangOptions().ObjCAutoRefCount &&
+        lparm->hasAttr<NSConsumedAttr>() != rparm->hasAttr<NSConsumedAttr>())
+      return false;
   }
   return true;
 }
@@ -1513,8 +1769,10 @@
 
   // We've seen a method with this name, see if we have already seen this type
   // signature.
-  for (ObjCMethodList *List = &Entry; List; List = List->Next)
-    if (MatchTwoMethodDeclarations(Method, List->Method)) {
+  for (ObjCMethodList *List = &Entry; List; List = List->Next) {
+    bool match = MatchTwoMethodDeclarations(Method, List->Method);
+
+    if (match) {
       ObjCMethodDecl *PrevObjCMethod = List->Method;
       PrevObjCMethod->setDefined(impl);
       // If a method is deprecated, push it in the global pool.
@@ -1531,6 +1789,7 @@
       }
       return;
     }
+  }
 
   // We have a new signature for an existing method - add it.
   // This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
@@ -1538,6 +1797,25 @@
   Entry.Next = new (Mem) ObjCMethodList(Method, Entry.Next);
 }
 
+/// Determines if this is an "acceptable" loose mismatch in the global
+/// method pool.  This exists mostly as a hack to get around certain
+/// global mismatches which we can't afford to make warnings / errors.
+/// Really, what we want is a way to take a method out of the global
+/// method pool.
+static bool isAcceptableMethodMismatch(ObjCMethodDecl *chosen,
+                                       ObjCMethodDecl *other) {
+  if (!chosen->isInstanceMethod())
+    return false;
+
+  Selector sel = chosen->getSelector();
+  if (!sel.isUnarySelector() || sel.getNameForSlot(0) != "length")
+    return false;
+
+  // Don't complain about mismatches for -length if the method we
+  // chose has an integral result type.
+  return (chosen->getResultType()->isIntegerType());
+}
+
 ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
                                                bool receiverIdOrClass,
                                                bool warn, bool instance) {
@@ -1551,32 +1829,52 @@
 
   ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
 
-  bool strictSelectorMatch = receiverIdOrClass && warn &&
-    (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl,
-                              R.getBegin()) != 
-      Diagnostic::Ignored);
   if (warn && MethList.Method && MethList.Next) {
-    bool issueWarning = false;
+    bool issueDiagnostic = false, issueError = false;
+
+    // We support a warning which complains about *any* difference in
+    // method signature.
+    bool strictSelectorMatch =
+      (receiverIdOrClass && warn &&
+       (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl,
+                                 R.getBegin()) != 
+      Diagnostic::Ignored));
     if (strictSelectorMatch)
       for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) {
-        // This checks if the methods differ in type mismatch.
-        if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, false, true))
-          issueWarning = true;
+        if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method,
+                                        MMS_strict)) {
+          issueDiagnostic = true;
+          break;
+        }
       }
 
-    if (!issueWarning)
+    // If we didn't see any strict differences, we won't see any loose
+    // differences.  In ARC, however, we also need to check for loose
+    // mismatches, because most of them are errors.
+    if (!strictSelectorMatch ||
+        (issueDiagnostic && getLangOptions().ObjCAutoRefCount))
       for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) {
-        // This checks if the methods differ by size & alignment.
-        if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, true))
-          issueWarning = true;
+        // This checks if the methods differ in type mismatch.
+        if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method,
+                                        MMS_loose) &&
+            !isAcceptableMethodMismatch(MethList.Method, Next->Method)) {
+          issueDiagnostic = true;
+          if (getLangOptions().ObjCAutoRefCount)
+            issueError = true;
+          break;
+        }
       }
 
-    if (issueWarning) {
-      if (strictSelectorMatch)
+    if (issueDiagnostic) {
+      if (issueError)
+        Diag(R.getBegin(), diag::err_arc_multiple_method_decl) << Sel << R;
+      else if (strictSelectorMatch)
         Diag(R.getBegin(), diag::warn_strict_multiple_method_decl) << Sel << R;
       else
         Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R;
-      Diag(MethList.Method->getLocStart(), diag::note_using)
+
+      Diag(MethList.Method->getLocStart(), 
+           issueError ? diag::note_possibility : diag::note_using)
         << MethList.Method->getSourceRange();
       for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next)
         Diag(Next->Method->getLocStart(), diag::note_also_found)
@@ -1804,6 +2102,7 @@
         DefaultSynthesizeProperties(S, IC, IDecl);
       ImplMethodsVsClassMethods(S, IC, IDecl);
       AtomicPropertySetterGetterRules(IC, IDecl);
+      DiagnoseOwningPropertyGetterSynthesis(IC);
   
       if (LangOpts.ObjCNonFragileABI2)
         while (IDecl->getSuperClass()) {
@@ -2112,7 +2411,11 @@
     mergeObjCMethodDecls(ObjCMethod, InterfaceMD);
   }
   
-  if (!ObjCMethod->hasRelatedResultType() && 
+  bool ARCError = false;
+  if (getLangOptions().ObjCAutoRefCount)
+    ARCError = CheckARCMethodDecl(*this, ObjCMethod);
+
+  if (!ObjCMethod->hasRelatedResultType() && !ARCError &&
       getLangOptions().ObjCInferRelatedResultType) {
     bool InferRelatedResultType = false;
     switch (ObjCMethod->getMethodFamily()) {
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index a2ad161..f0ecb58 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -87,7 +87,7 @@
   if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
     if (FD->isDeleted()) {
       Diag(Loc, diag::err_deleted_function_use);
-      Diag(D->getLocation(), diag::note_unavailable_here) << true;
+      Diag(D->getLocation(), diag::note_unavailable_here) << 1 << true;
       return true;
     }
   }
@@ -114,7 +114,8 @@
     else 
       Diag(Loc, diag::err_unavailable_message) 
         << D->getDeclName() << Message;
-    Diag(D->getLocation(), diag::note_unavailable_here) << 0;    
+    Diag(D->getLocation(), diag::note_unavailable_here) 
+      << isa<FunctionDecl>(D) << false;    
     break;
   }
 
@@ -437,7 +438,7 @@
 /// will warn if the resulting type is not a POD type, and rejects ObjC
 /// interfaces passed by value.
 ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
-                                            FunctionDecl *FDecl) {
+                                                  FunctionDecl *FDecl) {
   ExprResult ExprRes = DefaultArgumentPromotion(E);
   if (ExprRes.isInvalid())
     return ExprError();
@@ -456,7 +457,7 @@
                           << E->getType() << CT))
     return ExprError();
   
-  if (!E->getType()->isPODType()) {
+  if (!E->getType().isPODType(Context)) {
     // C++0x [expr.call]p7:
     //   Passing a potentially-evaluated argument of class type (Clause 9) 
     //   having a non-trivial copy constructor, a non-trivial move constructor,
@@ -471,6 +472,11 @@
           TrivialEnough = true;
       }
     }
+
+    if (!TrivialEnough &&
+        getLangOptions().ObjCAutoRefCount &&
+        E->getType()->isObjCLifetimeType())
+      TrivialEnough = true;
       
     if (TrivialEnough) {
       // Nothing to diagnose. This is okay.
@@ -1545,9 +1551,11 @@
       //   An id-expression that denotes a non-static data member or non-static
       //   member function of a class can only be used:
       //   (...)
-      //   - if that id-expression denotes a non-static data member and it appears in an unevaluated operand.
-      const Sema::ExpressionEvaluationContextRecord& record = SemaRef.ExprEvalContexts.back();
-      bool isUnevaluatedExpression = record.Context == Sema::Unevaluated;
+      //   - if that id-expression denotes a non-static data member and it
+      //     appears in an unevaluated operand.
+      const Sema::ExpressionEvaluationContextRecord& record
+        = SemaRef.ExprEvalContexts.back();
+      bool isUnevaluatedExpression = (record.Context == Sema::Unevaluated);
       if (isUnevaluatedExpression)
         return IMA_Mixed_StaticContext;
     }
@@ -4241,6 +4249,9 @@
     //   - an interface
     ObjCInterfaceDecl *IDecl = OTy->getInterface();
     if (!IDecl) {
+      if (getLangOptions().ObjCAutoRefCount &&
+          (OTy->isObjCId() || OTy->isObjCClass()))
+        goto fail;
       // There's an implicit 'isa' ivar on all objects.
       // But we only actually find it this way on objects of type 'id',
       // apparently.
@@ -4730,6 +4741,7 @@
     MarkDeclarationReferenced(Param->getDefaultArg()->getLocStart(), 
                     const_cast<CXXDestructorDecl*>(Temporary->getDestructor()));
     ExprTemporaries.push_back(Temporary);
+    ExprNeedsCleanups = true;
   }
 
   // We already type-checked the argument, so we know it works. 
@@ -4848,7 +4860,8 @@
 
       InitializedEntity Entity =
         Param? InitializedEntity::InitializeParameter(Context, Param)
-             : InitializedEntity::InitializeParameter(Context, ProtoArgType);
+             : InitializedEntity::InitializeParameter(Context, ProtoArgType,
+                                                      Proto->isArgConsumed(i));
       ExprResult ArgE = PerformCopyInitialization(Entity,
                                                   SourceLocation(),
                                                   Owned(Arg));
@@ -5171,7 +5184,8 @@
       if (Proto && i < Proto->getNumArgs()) {
         InitializedEntity Entity
           = InitializedEntity::InitializeParameter(Context, 
-                                                   Proto->getArgType(i));
+                                                   Proto->getArgType(i),
+                                                   Proto->isArgConsumed(i));
         ExprResult ArgE = PerformCopyInitialization(Entity,
                                                     SourceLocation(),
                                                     Owned(Arg));
@@ -5262,8 +5276,8 @@
   InitializedEntity Entity
     = InitializedEntity::InitializeTemporary(literalType);
   InitializationKind Kind
-    = InitializationKind::CreateCast(SourceRange(LParenLoc, RParenLoc),
-                                     /*IsCStyleCast=*/true);
+    = InitializationKind::CreateCStyleCast(LParenLoc, 
+                                           SourceRange(LParenLoc, RParenLoc));
   InitializationSequence InitSeq(*this, Entity, Kind, &literalExpr, 1);
   ExprResult Result = InitSeq.Perform(*this, Entity, Kind,
                                        MultiExprArg(*this, &literalExpr, 1),
@@ -5440,14 +5454,15 @@
 }
 
 /// CheckCastTypes - Check type constraints for casting between types.
-ExprResult Sema::CheckCastTypes(SourceRange TyR, QualType castType,
-                                Expr *castExpr, CastKind& Kind, ExprValueKind &VK,
+ExprResult Sema::CheckCastTypes(SourceLocation CastStartLoc, SourceRange TyR, 
+                                QualType castType, Expr *castExpr, 
+                                CastKind& Kind, ExprValueKind &VK,
                                 CXXCastPath &BasePath, bool FunctionalStyle) {
   if (castExpr->getType() == Context.UnknownAnyTy)
     return checkUnknownAnyCast(TyR, castType, castExpr, Kind, VK, BasePath);
 
   if (getLangOptions().CPlusPlus)
-    return CXXCheckCStyleCast(SourceRange(TyR.getBegin(),
+    return CXXCheckCStyleCast(SourceRange(CastStartLoc,
                                           castExpr->getLocEnd()), 
                               castType, VK, castExpr, Kind, BasePath,
                               FunctionalStyle);
@@ -5565,8 +5580,8 @@
 
   // If either type is a pointer, the other type has to be either an
   // integer or a pointer.
+  QualType castExprType = castExpr->getType();
   if (!castType->isArithmeticType()) {
-    QualType castExprType = castExpr->getType();
     if (!castExprType->isIntegralType(Context) && 
         castExprType->isArithmeticType()) {
       Diag(castExpr->getLocStart(),
@@ -5582,6 +5597,29 @@
     }
   }
 
+  if (getLangOptions().ObjCAutoRefCount) {
+    // Diagnose problems with Objective-C casts involving lifetime qualifiers.
+    CheckObjCARCConversion(SourceRange(CastStartLoc, castExpr->getLocEnd()), 
+                           castType, castExpr, CCK_CStyleCast);
+    
+    if (const PointerType *CastPtr = castType->getAs<PointerType>()) {
+      if (const PointerType *ExprPtr = castExprType->getAs<PointerType>()) {
+        Qualifiers CastQuals = CastPtr->getPointeeType().getQualifiers();
+        Qualifiers ExprQuals = ExprPtr->getPointeeType().getQualifiers();
+        if (CastPtr->getPointeeType()->isObjCLifetimeType() && 
+            ExprPtr->getPointeeType()->isObjCLifetimeType() &&
+            !CastQuals.compatiblyIncludesObjCLifetime(ExprQuals)) {
+          Diag(castExpr->getLocStart(), 
+               diag::err_typecheck_incompatible_lifetime)
+            << castExprType << castType << AA_Casting
+            << castExpr->getSourceRange();
+          
+          return ExprError();
+        }
+      }
+    }
+  }
+  
   castExprRes = Owned(castExpr);
   Kind = PrepareScalarCast(*this, castExprRes, castType);
   if (castExprRes.isInvalid())
@@ -5677,8 +5715,8 @@
   ExprValueKind VK = VK_RValue;
   CXXCastPath BasePath;
   ExprResult CastResult =
-    CheckCastTypes(SourceRange(LParenLoc, RParenLoc), Ty->getType(), castExpr,
-                   Kind, VK, BasePath);
+    CheckCastTypes(LParenLoc, SourceRange(LParenLoc, RParenLoc), Ty->getType(), 
+                   castExpr, Kind, VK, BasePath);
   if (CastResult.isInvalid())
     return ExprError();
   castExpr = CastResult.take();
@@ -6441,17 +6479,31 @@
   // qualifiers of the type *pointed to* by the right;
   Qualifiers lq;
 
+  // As a special case, 'non-__weak A *' -> 'non-__weak const *' is okay.
+  if (lhq.getObjCLifetime() != rhq.getObjCLifetime() &&
+      lhq.compatiblyIncludesObjCLifetime(rhq)) {
+    // Ignore lifetime for further calculation.
+    lhq.removeObjCLifetime();
+    rhq.removeObjCLifetime();
+  }
+
   if (!lhq.compatiblyIncludes(rhq)) {
     // Treat address-space mismatches as fatal.  TODO: address subspaces
     if (lhq.getAddressSpace() != rhq.getAddressSpace())
       ConvTy = Sema::IncompatiblePointerDiscardsQualifiers;
 
-    // It's okay to add or remove GC qualifiers when converting to
+    // It's okay to add or remove GC or lifetime qualifiers when converting to
     // and from void*.
-    else if (lhq.withoutObjCGCAttr().compatiblyIncludes(rhq.withoutObjCGCAttr())
+    else if (lhq.withoutObjCGCAttr().withoutObjCGLifetime()
+                        .compatiblyIncludes(
+                                rhq.withoutObjCGCAttr().withoutObjCGLifetime())
              && (lhptee->isVoidType() || rhptee->isVoidType()))
       ; // keep old
 
+    // Treat lifetime mismatches as fatal.
+    else if (lhq.getObjCLifetime() != rhq.getObjCLifetime())
+      ConvTy = Sema::IncompatiblePointerDiscardsQualifiers;
+    
     // For GCC compatibility, other qualifier mismatches are treated
     // as still compatible in C.
     else ConvTy = Sema::CompatiblePointerDiscardsQualifiers;
@@ -8118,7 +8170,40 @@
   unsigned Diag = 0;
   bool NeedType = false;
   switch (IsLV) { // C99 6.5.16p2
-  case Expr::MLV_ConstQualified: Diag = diag::err_typecheck_assign_const; break;
+  case Expr::MLV_ConstQualified:
+    Diag = diag::err_typecheck_assign_const;
+
+    // In ARC, use some specialized diagnostics for the times when we
+    // infer const.
+    if (S.getLangOptions().ObjCAutoRefCount) {
+      DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts());
+      if (declRef && isa<VarDecl>(declRef->getDecl())) {
+        VarDecl *var = cast<VarDecl>(declRef->getDecl());
+
+        // If the variable wasn't written with 'const', there are some
+        // cases where we infer const anyway:
+        //  - self
+        //  - fast enumeration variables
+        if (!var->getTypeSourceInfo() ||
+            !var->getTypeSourceInfo()->getType().isConstQualified()) {
+          ObjCMethodDecl *method = S.getCurMethodDecl();
+          if (method && var == method->getSelfDecl())
+            Diag = diag::err_typecheck_arr_assign_self;
+          else if (var->getType().getObjCLifetime()
+                     == Qualifiers::OCL_ExplicitNone)
+            Diag = diag::err_typecheck_arr_assign_enumeration;
+          SourceRange Assign;
+          if (Loc != OrigLoc)
+            Assign = SourceRange(OrigLoc, OrigLoc);
+          S.Diag(Loc, Diag) << E->getSourceRange() << Assign;
+          // We need to preserve the AST regardless, so migration tool 
+          // can do its job.
+          return false;
+        }
+      }
+    }
+
+    break;
   case Expr::MLV_ArrayType:
     Diag = diag::err_typecheck_array_not_modifiable_lvalue;
     NeedType = true;
@@ -8233,6 +8318,13 @@
           << SourceRange(UO->getOperatorLoc(), UO->getOperatorLoc());
       }
     }
+
+    if (ConvTy == Compatible) {
+      if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong)
+        checkRetainCycles(LHS, RHS.get());
+      else
+        checkUnsafeAssigns(Loc, LHSType, RHS.get());
+    }
   } else {
     // Compound assignment "x += y"
     ConvTy = CheckAssignmentConstraints(Loc, LHSType, RHSType);
@@ -8419,6 +8511,8 @@
          LHS.get()->getObjectKind() == OK_ObjCProperty);
   const ObjCPropertyRefExpr *PropRef = LHS.get()->getObjCProperty();
 
+  bool Consumed = false;
+
   if (PropRef->isImplicitProperty()) {
     // If using property-dot syntax notation for assignment, and there is a
     // setter, RHS expression is being passed to the setter argument. So,
@@ -8426,6 +8520,8 @@
     if (const ObjCMethodDecl *SetterMD = PropRef->getImplicitPropertySetter()) {
       ObjCMethodDecl::param_iterator P = SetterMD->param_begin();
       LHSTy = (*P)->getType();
+      Consumed = (getLangOptions().ObjCAutoRefCount &&
+                  (*P)->hasAttr<NSConsumedAttr>());
 
     // Otherwise, if the getter returns an l-value, just call that.
     } else {
@@ -8437,14 +8533,26 @@
         return;
       }
     }
+  } else if (getLangOptions().ObjCAutoRefCount) {
+    const ObjCMethodDecl *setter
+      = PropRef->getExplicitProperty()->getSetterMethodDecl();
+    if (setter) {
+      ObjCMethodDecl::param_iterator P = setter->param_begin();
+      LHSTy = (*P)->getType();
+      Consumed = (*P)->hasAttr<NSConsumedAttr>();
+    }
   }
 
-  if (getLangOptions().CPlusPlus && LHSTy->isRecordType()) {
+  if ((getLangOptions().CPlusPlus && LHSTy->isRecordType()) ||
+      getLangOptions().ObjCAutoRefCount) {
     InitializedEntity Entity = 
-    InitializedEntity::InitializeParameter(Context, LHSTy);
+      InitializedEntity::InitializeParameter(Context, LHSTy, Consumed);
     ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), RHS);
-    if (!ArgE.isInvalid())
+    if (!ArgE.isInvalid()) {
       RHS = ArgE;
+      if (getLangOptions().ObjCAutoRefCount && !PropRef->isSuperReceiver())
+        checkRetainCycles(const_cast<Expr*>(PropRef->getBase()), RHS.get());
+    }
   }
 }
   
@@ -9293,6 +9401,29 @@
                                        Context.getPointerType(Context.VoidTy)));
 }
 
+/// Given the last statement in a statement-expression, check whether
+/// the result is a producing expression (like a call to an
+/// ns_returns_retained function) and, if so, rebuild it to hoist the
+/// release out of the full-expression.  Otherwise, return null.
+/// Cannot fail.
+static Expr *maybeRebuildARCConsumingStmt(Stmt *s) {
+  // Should always be wrapped with one of these.
+  ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(s);
+  if (!cleanups) return 0;
+
+  ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(cleanups->getSubExpr());
+  if (!cast || cast->getCastKind() != CK_ObjCConsumeObject)
+    return 0;
+
+  // Splice out the cast.  This shouldn't modify any interesting
+  // features of the statement.
+  Expr *producer = cast->getSubExpr();
+  assert(producer->getType() == cast->getType());
+  assert(producer->getValueKind() == cast->getValueKind());
+  cleanups->setSubExpr(producer);
+  return cleanups;
+}
+
 ExprResult
 Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
                     SourceLocation RPLoc) { // "({..})"
@@ -9320,6 +9451,7 @@
       LastLabelStmt = Label;
       LastStmt = Label->getSubStmt();
     }
+
     if (Expr *LastE = dyn_cast<Expr>(LastStmt)) {
       // Do function/array conversion on the last expression, but not
       // lvalue-to-rvalue.  However, initialize an unqualified type.
@@ -9329,12 +9461,24 @@
       Ty = LastExpr.get()->getType().getUnqualifiedType();
 
       if (!Ty->isDependentType() && !LastExpr.get()->isTypeDependent()) {
-        LastExpr = PerformCopyInitialization(
+        // In ARC, if the final expression ends in a consume, splice
+        // the consume out and bind it later.  In the alternate case
+        // (when dealing with a retainable type), the result
+        // initialization will create a produce.  In both cases the
+        // result will be +1, and we'll need to balance that out with
+        // a bind.
+        if (Expr *rebuiltLastStmt
+              = maybeRebuildARCConsumingStmt(LastExpr.get())) {
+          LastExpr = rebuiltLastStmt;
+        } else {
+          LastExpr = PerformCopyInitialization(
                             InitializedEntity::InitializeResult(LPLoc, 
                                                                 Ty,
                                                                 false),
                                                    SourceLocation(),
-                                             LastExpr);
+                                               LastExpr);
+        }
+
         if (LastExpr.isInvalid())
           return ExprError();
         if (LastExpr.get() != 0) {
@@ -9776,7 +9920,7 @@
   // If we don't have a function type, just build one from nothing.
   } else {
     FunctionProtoType::ExtProtoInfo EPI;
-    EPI.ExtInfo = FunctionType::ExtInfo(NoReturn, false, 0, CC_Default);
+    EPI.ExtInfo = FunctionType::ExtInfo().withNoReturn(NoReturn);
     BlockTy = Context.getFunctionType(RetTy, 0, 0, EPI);
   }
 
@@ -9785,7 +9929,8 @@
   BlockTy = Context.getBlockPointerType(BlockTy);
 
   // If needed, diagnose invalid gotos and switches in the block.
-  if (getCurFunction()->NeedsScopeChecking() && !hasAnyErrorsInThisFunction())
+  if (getCurFunction()->NeedsScopeChecking() &&
+      !hasAnyUnrecoverableErrorsInThisFunction())
     DiagnoseInvalidJumps(cast<CompoundStmt>(Body));
 
   BSI->TheDecl->setBody(cast<CompoundStmt>(Body));
@@ -9849,7 +9994,7 @@
           << TInfo->getTypeLoc().getSourceRange()))
       return ExprError();
 
-    if (!TInfo->getType()->isPODType())
+    if (!TInfo->getType().isPODType(Context))
       Diag(TInfo->getTypeLoc().getBeginLoc(),
           diag::warn_second_parameter_to_va_arg_not_pod)
         << TInfo->getType()
@@ -9948,6 +10093,11 @@
     if (lhq.getAddressSpace() != rhq.getAddressSpace()) {
       DiagKind = diag::err_typecheck_incompatible_address_space;
       break;
+
+
+    } else if (lhq.getObjCLifetime() != rhq.getObjCLifetime()) {
+      DiagKind = diag::err_typecheck_incompatible_lifetime;
+      break;
     }
 
     llvm_unreachable("unknown error case for discarding qualifiers!");
@@ -10062,7 +10212,10 @@
 void
 Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) {
   ExprEvalContexts.push_back(
-        ExpressionEvaluationContextRecord(NewContext, ExprTemporaries.size()));
+             ExpressionEvaluationContextRecord(NewContext,
+                                               ExprTemporaries.size(),
+                                               ExprNeedsCleanups));
+  ExprNeedsCleanups = false;
 }
 
 void
@@ -10097,15 +10250,27 @@
   // temporaries that we may have created as part of the evaluation of
   // the expression in that context: they aren't relevant because they
   // will never be constructed.
-  if (Rec.Context == Unevaluated &&
-      ExprTemporaries.size() > Rec.NumTemporaries)
+  if (Rec.Context == Unevaluated) {
     ExprTemporaries.erase(ExprTemporaries.begin() + Rec.NumTemporaries,
                           ExprTemporaries.end());
+    ExprNeedsCleanups = Rec.ParentNeedsCleanups;
+
+  // Otherwise, merge the contexts together.
+  } else {
+    ExprNeedsCleanups |= Rec.ParentNeedsCleanups;
+  }
 
   // Destroy the popped expression evaluation record.
   Rec.Destroy();
 }
 
+void Sema::DiscardCleanupsInEvaluationContext() {
+  ExprTemporaries.erase(
+              ExprTemporaries.begin() + ExprEvalContexts.back().NumTemporaries,
+              ExprTemporaries.end());
+  ExprNeedsCleanups = false;
+}
+
 /// \brief Note that the given declaration was referenced in the source code.
 ///
 /// This routine should be invoke whenever a given declaration is referenced
@@ -10399,7 +10564,7 @@
 /// during overload resolution or within sizeof/alignof/typeof/typeid.
 bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *stmt,
                                const PartialDiagnostic &PD) {
-  switch (ExprEvalContexts.back().Context ) {
+  switch (ExprEvalContexts.back().Context) {
   case Unevaluated:
     // The argument will never be evaluated, so don't complain.
     break;
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 2f5a890..c796f12 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -691,7 +691,8 @@
     ExprValueKind VK = VK_RValue;
     CXXCastPath BasePath;
     ExprResult CastExpr =
-      CheckCastTypes(TInfo->getTypeLoc().getSourceRange(), Ty, Exprs[0],
+      CheckCastTypes(TInfo->getTypeLoc().getBeginLoc(),
+                     TInfo->getTypeLoc().getSourceRange(), Ty, Exprs[0],
                      Kind, VK, BasePath,
                      /*FunctionalStyle=*/true);
     if (CastExpr.isInvalid())
@@ -902,8 +903,16 @@
   if (CheckAllocatedType(AllocType, TypeRange.getBegin(), TypeRange))
     return ExprError();
 
-  QualType ResultType = Context.getPointerType(AllocType);
+  // In ARC, infer 'retaining' for the allocated 
+  if (getLangOptions().ObjCAutoRefCount &&
+      AllocType.getObjCLifetime() == Qualifiers::OCL_None &&
+      AllocType->isObjCLifetimeType()) {
+    AllocType = Context.getLifetimeQualifiedType(AllocType,
+                                    AllocType->getObjCARCImplicitLifetime());
+  }
 
+  QualType ResultType = Context.getPointerType(AllocType);
+    
   // C++ 5.3.4p6: "The expression in a direct-new-declarator shall have integral
   //   or enumeration type with a non-negative value."
   if (ArraySize && !ArraySize->isTypeDependent()) {
@@ -964,6 +973,14 @@
       }
     }
 
+    // ARC: warn about ABI issues.
+    if (getLangOptions().ObjCAutoRefCount) {
+      QualType BaseAllocType = Context.getBaseElementType(AllocType);
+      if (BaseAllocType.hasStrongOrWeakObjCLifetime())
+        Diag(StartLoc, diag::warn_err_new_delete_object_array)
+          << 0 << BaseAllocType;
+    }
+
     // Note that we do *not* convert the argument in any way.  It can
     // be signed, larger than size_t, whatever.
   }
@@ -1122,6 +1139,15 @@
   else if (unsigned AddressSpace = AllocType.getAddressSpace())
     return Diag(Loc, diag::err_address_space_qualified_new)
       << AllocType.getUnqualifiedType() << AddressSpace;
+  else if (getLangOptions().ObjCAutoRefCount) {
+    if (const ArrayType *AT = Context.getAsArrayType(AllocType)) {
+      QualType BaseAllocType = Context.getBaseElementType(AT);
+      if (BaseAllocType.getObjCLifetime() == Qualifiers::OCL_None &&
+          BaseAllocType->isObjCLifetimeType())
+        return Diag(Loc, diag::err_arc_new_array_without_lifetime)
+          << BaseAllocType;
+    }
+  }
            
   return false;
 }
@@ -1774,8 +1800,9 @@
     //   delete-expression; it is not necessary to cast away the constness
     //   (5.2.11) of the pointer expression before it is used as the operand
     //   of the delete-expression. ]
-    Ex = ImpCastExprToType(Ex.take(), Context.getPointerType(Context.VoidTy),
-                      CK_NoOp);
+    if (!Context.hasSameType(Ex.get()->getType(), Context.VoidPtrTy))
+      Ex = Owned(ImplicitCastExpr::Create(Context, Context.VoidPtrTy, CK_NoOp,
+                                          Ex.take(), 0, VK_RValue));
 
     if (Pointee->isArrayType() && !ArrayForm) {
       Diag(StartLoc, diag::warn_delete_array_type)
@@ -1830,6 +1857,14 @@
         if (!dtor || !dtor->isVirtual())
           Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem;
       }
+
+    } else if (getLangOptions().ObjCAutoRefCount &&
+               PointeeElem->isObjCLifetimeType() &&
+               (PointeeElem.getObjCLifetime() == Qualifiers::OCL_Strong ||
+                PointeeElem.getObjCLifetime() == Qualifiers::OCL_Weak) &&
+               ArrayForm) {
+      Diag(StartLoc, diag::warn_err_new_delete_object_array)
+        << 1 << PointeeElem;
     }
 
     if (!OperatorDelete) {
@@ -1988,11 +2023,12 @@
 ExprResult
 Sema::PerformImplicitConversion(Expr *From, QualType ToType,
                                 const ImplicitConversionSequence &ICS,
-                                AssignmentAction Action, bool CStyle) {
+                                AssignmentAction Action, 
+                                CheckedConversionKind CCK) {
   switch (ICS.getKind()) {
   case ImplicitConversionSequence::StandardConversion: {
     ExprResult Res = PerformImplicitConversion(From, ToType, ICS.Standard,
-                                               Action, CStyle);
+                                               Action, CCK);
     if (Res.isInvalid())
       return ExprError();
     From = Res.take();
@@ -2027,7 +2063,7 @@
         ExprResult Res =
           PerformImplicitConversion(From, BeforeToType,
                                     ICS.UserDefined.Before, AA_Converting,
-                                    CStyle);
+                                    CCK);
         if (Res.isInvalid())
           return ExprError();
         From = Res.take();
@@ -2047,7 +2083,7 @@
       From = CastArg.take();
 
       return PerformImplicitConversion(From, ToType, ICS.UserDefined.After,
-                                       AA_Converting, CStyle);
+                                       AA_Converting, CCK);
   }
 
   case ImplicitConversionSequence::AmbiguousConversion:
@@ -2076,13 +2112,16 @@
 ExprResult
 Sema::PerformImplicitConversion(Expr *From, QualType ToType,
                                 const StandardConversionSequence& SCS,
-                                AssignmentAction Action, bool CStyle) {
+                                AssignmentAction Action, 
+                                CheckedConversionKind CCK) {
+  bool CStyle = (CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast);
+  
   // Overall FIXME: we are recomputing too many types here and doing far too
   // much extra work. What this means is that we need to keep track of more
   // information that is computed when we try the implicit conversion initially,
   // so that we don't need to recompute anything here.
   QualType FromType = From->getType();
-
+  
   if (SCS.CopyConstructor) {
     // FIXME: When can ToType be a reference type?
     assert(!ToType->isReferenceType());
@@ -2149,12 +2188,14 @@
 
   case ICK_Array_To_Pointer:
     FromType = Context.getArrayDecayedType(FromType);
-    From = ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay).take();
+    From = ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay, 
+                             VK_RValue, /*BasePath=*/0, CCK).take();
     break;
 
   case ICK_Function_To_Pointer:
     FromType = Context.getPointerType(FromType);
-    From = ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay).take();
+    From = ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay, 
+                             VK_RValue, /*BasePath=*/0, CCK).take();
     break;
 
   default:
@@ -2178,17 +2219,20 @@
     if (CheckExceptionSpecCompatibility(From, ToType))
       return ExprError();
 
-    From = ImpCastExprToType(From, ToType, CK_NoOp).take();
+    From = ImpCastExprToType(From, ToType, CK_NoOp, 
+                             VK_RValue, /*BasePath=*/0, CCK).take();
     break;
 
   case ICK_Integral_Promotion:
   case ICK_Integral_Conversion:
-    From = ImpCastExprToType(From, ToType, CK_IntegralCast).take();
+    From = ImpCastExprToType(From, ToType, CK_IntegralCast, 
+                             VK_RValue, /*BasePath=*/0, CCK).take();
     break;
 
   case ICK_Floating_Promotion:
   case ICK_Floating_Conversion:
-    From = ImpCastExprToType(From, ToType, CK_FloatingCast).take();
+    From = ImpCastExprToType(From, ToType, CK_FloatingCast, 
+                             VK_RValue, /*BasePath=*/0, CCK).take();
     break;
 
   case ICK_Complex_Promotion:
@@ -2206,21 +2250,26 @@
     } else {
       CK = CK_IntegralComplexCast;
     }
-    From = ImpCastExprToType(From, ToType, CK).take();
+    From = ImpCastExprToType(From, ToType, CK, 
+                             VK_RValue, /*BasePath=*/0, CCK).take();
     break;
   }
 
   case ICK_Floating_Integral:
     if (ToType->isRealFloatingType())
-      From = ImpCastExprToType(From, ToType, CK_IntegralToFloating).take();
+      From = ImpCastExprToType(From, ToType, CK_IntegralToFloating, 
+                               VK_RValue, /*BasePath=*/0, CCK).take();
     else
-      From = ImpCastExprToType(From, ToType, CK_FloatingToIntegral).take();
+      From = ImpCastExprToType(From, ToType, CK_FloatingToIntegral, 
+                               VK_RValue, /*BasePath=*/0, CCK).take();
     break;
 
   case ICK_Compatible_Conversion:
-    From = ImpCastExprToType(From, ToType, CK_NoOp).take();
+      From = ImpCastExprToType(From, ToType, CK_NoOp, 
+                               VK_RValue, /*BasePath=*/0, CCK).take();
     break;
 
+  case ICK_Writeback_Conversion:
   case ICK_Pointer_Conversion: {
     if (SCS.IncompatibleObjC && Action != AA_Casting) {
       // Diagnose incompatible Objective-C conversions
@@ -2234,7 +2283,7 @@
              diag::ext_typecheck_convert_incompatible_pointer)
           << From->getType() << ToType << Action
           << From->getSourceRange();
-      
+
       if (From->getType()->isObjCObjectPointerType() &&
           ToType->isObjCObjectPointerType())
         EmitRelatedResultTypeNote(From);
@@ -2244,7 +2293,8 @@
     CXXCastPath BasePath;
     if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle))
       return ExprError();
-    From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath).take();
+    From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK)
+             .take();
     break;
   }
 
@@ -2255,13 +2305,15 @@
       return ExprError();
     if (CheckExceptionSpecCompatibility(From, ToType))
       return ExprError();
-    From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath).take();
+    From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK)
+             .take();
     break;
   }
 
   case ICK_Boolean_Conversion:
     From = ImpCastExprToType(From, Context.BoolTy,
-                             ScalarTypeToBooleanCastKind(FromType)).take();
+                             ScalarTypeToBooleanCastKind(FromType), 
+                             VK_RValue, /*BasePath=*/0, CCK).take();
     break;
 
   case ICK_Derived_To_Base: {
@@ -2276,16 +2328,18 @@
 
     From = ImpCastExprToType(From, ToType.getNonReferenceType(),
                       CK_DerivedToBase, CastCategory(From),
-                      &BasePath).take();
+                      &BasePath, CCK).take();
     break;
   }
 
   case ICK_Vector_Conversion:
-    From = ImpCastExprToType(From, ToType, CK_BitCast).take();
+    From = ImpCastExprToType(From, ToType, CK_BitCast, 
+                             VK_RValue, /*BasePath=*/0, CCK).take();
     break;
 
   case ICK_Vector_Splat:
-    From = ImpCastExprToType(From, ToType, CK_VectorSplat).take();
+    From = ImpCastExprToType(From, ToType, CK_VectorSplat, 
+                             VK_RValue, /*BasePath=*/0, CCK).take();
     break;
 
   case ICK_Complex_Real:
@@ -2321,27 +2375,30 @@
       // _Complex x -> x
       From = ImpCastExprToType(From, ElType,
                    isFloatingComplex ? CK_FloatingComplexToReal
-                                     : CK_IntegralComplexToReal).take();
+                                     : CK_IntegralComplexToReal, 
+                               VK_RValue, /*BasePath=*/0, CCK).take();
 
       // x -> y
       if (Context.hasSameUnqualifiedType(ElType, ToType)) {
         // do nothing
       } else if (ToType->isRealFloatingType()) {
         From = ImpCastExprToType(From, ToType,
-                isFloatingComplex ? CK_FloatingCast : CK_IntegralToFloating).take();
+                   isFloatingComplex ? CK_FloatingCast : CK_IntegralToFloating, 
+                                 VK_RValue, /*BasePath=*/0, CCK).take();
       } else {
         assert(ToType->isIntegerType());
         From = ImpCastExprToType(From, ToType,
-                isFloatingComplex ? CK_FloatingToIntegral : CK_IntegralCast).take();
+                   isFloatingComplex ? CK_FloatingToIntegral : CK_IntegralCast, 
+                                 VK_RValue, /*BasePath=*/0, CCK).take();
       }
     }
     break;
   
   case ICK_Block_Pointer_Conversion: {
-      From = ImpCastExprToType(From, ToType.getUnqualifiedType(), CK_BitCast,
-                               VK_RValue).take();
-      break;
-    }
+    From = ImpCastExprToType(From, ToType.getUnqualifiedType(), CK_BitCast,
+                             VK_RValue, /*BasePath=*/0, CCK).take();
+    break;
+  }
       
   case ICK_TransparentUnionConversion: {
     ExprResult FromRes = Owned(From);
@@ -2376,7 +2433,7 @@
     ExprValueKind VK = ToType->isReferenceType() ?
                                   CastCategory(From) : VK_RValue;
     From = ImpCastExprToType(From, ToType.getNonLValueExprType(Context),
-                             CK_NoOp, VK).take();
+                             CK_NoOp, VK, /*BasePath=*/0, CCK).take();
 
     if (SCS.DeprecatedStringLiteralToCharPtr &&
         !getLangOptions().WritableStrings)
@@ -2553,6 +2610,23 @@
   case UTT_IsObject:
     return T->isObjectType();
   case UTT_IsScalar:
+    // Note: semantic analysis depends on Objective-C lifetime types to be
+    // considered scalar types. However, such types do not actually behave
+    // like scalar types at run time (since they may require retain/release
+    // operations), so we report them as non-scalar.
+    if (T->isObjCLifetimeType()) {
+      switch (T.getObjCLifetime()) {
+      case Qualifiers::OCL_None:
+      case Qualifiers::OCL_ExplicitNone:
+        return true;
+
+      case Qualifiers::OCL_Strong:
+      case Qualifiers::OCL_Weak:
+      case Qualifiers::OCL_Autoreleasing:
+        return false;
+      }
+    }
+      
     return T->isScalarType();
   case UTT_IsCompound:
     return T->isCompoundType();
@@ -2566,13 +2640,13 @@
   case UTT_IsVolatile:
     return T.isVolatileQualified();
   case UTT_IsTrivial:
-    return T->isTrivialType();
+    return T.isTrivialType(Self.Context);
   case UTT_IsTriviallyCopyable:
-    return T->isTriviallyCopyableType();
+    return T.isTriviallyCopyableType(Self.Context);
   case UTT_IsStandardLayout:
     return T->isStandardLayoutType();
   case UTT_IsPOD:
-    return T->isPODType();
+    return T.isPODType(Self.Context);
   case UTT_IsLiteral:
     return T->isLiteralType();
   case UTT_IsEmpty:
@@ -2605,7 +2679,7 @@
     //   If __is_pod (type) is true then the trait is true, else if type is
     //   a cv class or union type (or array thereof) with a trivial default
     //   constructor ([class.ctor]) then the trait is true, else it is false.
-    if (T->isPODType())
+    if (T.isPODType(Self.Context))
       return true;
     if (const RecordType *RT =
           C.getBaseElementType(T)->getAs<RecordType>())
@@ -2617,7 +2691,7 @@
     //   the trait is true, else if type is a cv class or union type
     //   with a trivial copy constructor ([class.copy]) then the trait
     //   is true, else it is false.
-    if (T->isPODType() || T->isReferenceType())
+    if (T.isPODType(Self.Context) || T->isReferenceType())
       return true;
     if (const RecordType *RT = T->getAs<RecordType>())
       return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyConstructor();
@@ -2637,7 +2711,7 @@
 
     if (C.getBaseElementType(T).isConstQualified())
       return false;
-    if (T->isPODType())
+    if (T.isPODType(Self.Context))
       return true;
     if (const RecordType *RT = T->getAs<RecordType>())
       return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyAssignment();
@@ -2649,8 +2723,14 @@
     //   type (or array thereof) with a trivial destructor
     //   ([class.dtor]) then the trait is true, else it is
     //   false.
-    if (T->isPODType() || T->isReferenceType())
+    if (T.isPODType(Self.Context) || T->isReferenceType())
       return true;
+      
+    // Objective-C++ ARC: autorelease types don't require destruction.
+    if (T->isObjCLifetimeType() && 
+        T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing)
+      return true;
+      
     if (const RecordType *RT =
           C.getBaseElementType(T)->getAs<RecordType>())
       return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor();
@@ -2668,8 +2748,8 @@
       return false;
     if (T->isReferenceType())
       return false;
-    if (T->isPODType())
-      return true;
+    if (T.isPODType(Self.Context) || T->isObjCLifetimeType())
+      return true;     
     if (const RecordType *RT = T->getAs<RecordType>()) {
       CXXRecordDecl* RD = cast<CXXRecordDecl>(RT->getDecl());
       if (RD->hasTrivialCopyAssignment())
@@ -2704,7 +2784,7 @@
     //   if type is a cv class or union type with copy constructors that are
     //   known not to throw an exception then the trait is true, else it is
     //   false.
-    if (T->isPODType() || T->isReferenceType())
+    if (T.isPODType(C) || T->isReferenceType() || T->isObjCLifetimeType())
       return true;
     if (const RecordType *RT = T->getAs<RecordType>()) {
       CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
@@ -2744,7 +2824,7 @@
     //   true, else if type is a cv class or union type (or array
     //   thereof) with a default constructor that is known not to
     //   throw an exception then the trait is true, else it is false.
-    if (T->isPODType())
+    if (T.isPODType(C) || T->isObjCLifetimeType())
       return true;
     if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>()) {
       CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
@@ -3828,34 +3908,104 @@
   if (!E)
     return ExprError();
 
-  if (!Context.getLangOptions().CPlusPlus)
+  assert(!isa<CXXBindTemporaryExpr>(E) && "Double-bound temporary?");
+
+  // If the result is a glvalue, we shouldn't bind it.
+  if (!E->isRValue())
     return Owned(E);
 
-  assert(!isa<CXXBindTemporaryExpr>(E) && "Double-bound temporary?");
+  // In ARC, calls that return a retainable type can return retained,
+  // in which case we have to insert a consuming cast.
+  if (getLangOptions().ObjCAutoRefCount &&
+      E->getType()->isObjCRetainableType()) {
+
+    bool ReturnsRetained;
+
+    // For actual calls, we compute this by examining the type of the
+    // called value.
+    if (CallExpr *Call = dyn_cast<CallExpr>(E)) {
+      Expr *Callee = Call->getCallee()->IgnoreParens();
+      QualType T = Callee->getType();
+
+      if (T == Context.BoundMemberTy) {
+        // Handle pointer-to-members.
+        if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(Callee))
+          T = BinOp->getRHS()->getType();
+        else if (MemberExpr *Mem = dyn_cast<MemberExpr>(Callee))
+          T = Mem->getMemberDecl()->getType();
+      }
+      
+      if (const PointerType *Ptr = T->getAs<PointerType>())
+        T = Ptr->getPointeeType();
+      else if (const BlockPointerType *Ptr = T->getAs<BlockPointerType>())
+        T = Ptr->getPointeeType();
+      else if (const MemberPointerType *MemPtr = T->getAs<MemberPointerType>())
+        T = MemPtr->getPointeeType();
+      
+      const FunctionType *FTy = T->getAs<FunctionType>();
+      assert(FTy && "call to value not of function type?");
+      ReturnsRetained = FTy->getExtInfo().getProducesResult();
+
+    // ActOnStmtExpr arranges things so that StmtExprs of retainable
+    // type always produce a +1 object.
+    } else if (isa<StmtExpr>(E)) {
+      ReturnsRetained = true;
+
+    // For message sends and property references, we try to find an
+    // actual method.  FIXME: we should infer retention by selector in
+    // cases where we don't have an actual method.
+    } else {
+      Decl *D = 0;
+      if (ObjCMessageExpr *Send = dyn_cast<ObjCMessageExpr>(E)) {
+        D = Send->getMethodDecl();
+      } else {
+        CastExpr *CE = cast<CastExpr>(E);
+        // FIXME. What other cast kinds to check for?
+        if (CE->getCastKind() == CK_ObjCProduceObject ||
+            CE->getCastKind() == CK_LValueToRValue)
+          return MaybeBindToTemporary(CE->getSubExpr());
+        assert(CE->getCastKind() == CK_GetObjCProperty);
+        const ObjCPropertyRefExpr *PRE = CE->getSubExpr()->getObjCProperty();
+        D = (PRE->isImplicitProperty() ? PRE->getImplicitPropertyGetter() : 0);
+      }
+
+      ReturnsRetained = (D && D->hasAttr<NSReturnsRetainedAttr>());
+    }
+
+    if (ReturnsRetained) {
+      ExprNeedsCleanups = true;
+      E = ImplicitCastExpr::Create(Context, E->getType(),
+                                   CK_ObjCConsumeObject, E, 0,
+                                   VK_RValue);
+    }
+    return Owned(E);
+  }
+
+  if (!getLangOptions().CPlusPlus)
+    return Owned(E);
 
   const RecordType *RT = E->getType()->getAs<RecordType>();
   if (!RT)
     return Owned(E);
 
-  // If the result is a glvalue, we shouldn't bind it.
-  if (E->Classify(Context).isGLValue())
-    return Owned(E);
-
   // That should be enough to guarantee that this type is complete.
   // If it has a trivial destructor, we can avoid the extra copy.
   CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
   if (RD->isInvalidDecl() || RD->hasTrivialDestructor())
     return Owned(E);
 
-  CXXTemporary *Temp = CXXTemporary::Create(Context, LookupDestructor(RD));
-  ExprTemporaries.push_back(Temp);
-  if (CXXDestructorDecl *Destructor = LookupDestructor(RD)) {
+  CXXDestructorDecl *Destructor = LookupDestructor(RD);
+
+  CXXTemporary *Temp = CXXTemporary::Create(Context, Destructor);
+  if (Destructor) {
     MarkDeclarationReferenced(E->getExprLoc(), Destructor);
     CheckDestructorAccess(E->getExprLoc(), Destructor,
                           PDiag(diag::err_access_dtor_temp)
                             << E->getType());
+
+    ExprTemporaries.push_back(Temp);
+    ExprNeedsCleanups = true;
   }
-  // FIXME: Add the temporary to the temporaries vector.
   return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E));
 }
 
@@ -3864,14 +4014,16 @@
 
   unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries;
   assert(ExprTemporaries.size() >= FirstTemporary);
-  if (ExprTemporaries.size() == FirstTemporary)
+  assert(ExprNeedsCleanups || ExprTemporaries.size() == FirstTemporary);
+  if (!ExprNeedsCleanups)
     return SubExpr;
 
   Expr *E = ExprWithCleanups::Create(Context, SubExpr,
-                                     &ExprTemporaries[FirstTemporary],
+                                     ExprTemporaries.begin() + FirstTemporary,
                                      ExprTemporaries.size() - FirstTemporary);
   ExprTemporaries.erase(ExprTemporaries.begin() + FirstTemporary,
                         ExprTemporaries.end());
+  ExprNeedsCleanups = false;
 
   return E;
 }
@@ -3887,9 +4039,7 @@
 Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) {
   assert(SubStmt && "sub statement can't be null!");
 
-  unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries;
-  assert(ExprTemporaries.size() >= FirstTemporary);
-  if (ExprTemporaries.size() == FirstTemporary)
+  if (!ExprNeedsCleanups)
     return SubStmt;
 
   // FIXME: In order to attach the temporaries, wrap the statement into
@@ -4047,17 +4197,35 @@
     QualType DestructedType = DestructedTypeInfo->getType();
     SourceLocation DestructedTypeStart
       = DestructedTypeInfo->getTypeLoc().getLocalSourceRange().getBegin();
-    if (!DestructedType->isDependentType() && !ObjectType->isDependentType() &&
-        !Context.hasSameUnqualifiedType(DestructedType, ObjectType)) {
-      Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch)
-        << ObjectType << DestructedType << Base->getSourceRange()
-        << DestructedTypeInfo->getTypeLoc().getLocalSourceRange();
+    if (!DestructedType->isDependentType() && !ObjectType->isDependentType()) {
+      if (!Context.hasSameUnqualifiedType(DestructedType, ObjectType)) {
+        Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch)
+          << ObjectType << DestructedType << Base->getSourceRange()
+          << DestructedTypeInfo->getTypeLoc().getLocalSourceRange();
 
-      // Recover by setting the destructed type to the object type.
-      DestructedType = ObjectType;
-      DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType,
+        // Recover by setting the destructed type to the object type.
+        DestructedType = ObjectType;
+        DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType,
                                                            DestructedTypeStart);
-      Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo);
+        Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo);
+      } else if (DestructedType.getObjCLifetime() != 
+                                                ObjectType.getObjCLifetime()) {
+        
+        if (DestructedType.getObjCLifetime() == Qualifiers::OCL_None) {
+          // Okay: just pretend that the user provided the correctly-qualified
+          // type.
+        } else {
+          Diag(DestructedTypeStart, diag::err_arc_pseudo_dtor_inconstant_quals)
+            << ObjectType << DestructedType << Base->getSourceRange()
+            << DestructedTypeInfo->getTypeLoc().getLocalSourceRange();
+        }
+        
+        // Recover by setting the destructed type to the object type.
+        DestructedType = ObjectType;
+        DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType,
+                                                           DestructedTypeStart);
+        Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo);
+      }
     }
   }
 
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index cb5c1e0..1d1f6ae 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -19,6 +19,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/ExprObjC.h"
+#include "clang/AST/StmtVisitor.h"
 #include "clang/AST/TypeLoc.h"
 #include "llvm/ADT/SmallString.h"
 #include "clang/Lex/Preprocessor.h"
@@ -182,6 +183,29 @@
   if (Pos == ReferencedSelectors.end())
     ReferencedSelectors.insert(std::make_pair(Sel, SelLoc));
 
+  // In ARC, forbid the user from using @selector for 
+  // retain/release/autorelease/dealloc/retainCount.
+  if (getLangOptions().ObjCAutoRefCount) {
+    switch (Sel.getMethodFamily()) {
+    case OMF_retain:
+    case OMF_release:
+    case OMF_autorelease:
+    case OMF_retainCount:
+    case OMF_dealloc:
+      Diag(AtLoc, diag::err_arc_illegal_selector) << 
+        Sel << SourceRange(LParenLoc, RParenLoc);
+      break;
+
+    case OMF_None:
+    case OMF_alloc:
+    case OMF_copy:
+    case OMF_init:
+    case OMF_mutableCopy:
+    case OMF_new:
+    case OMF_self:
+      break;
+    }
+  }
   QualType Ty = Context.getObjCSelType();
   return new (Context) ObjCSelectorExpr(Ty, Sel, AtLoc, RParenLoc);
 }
@@ -321,8 +345,12 @@
       Args[i] = Result.take();
     }
 
-    unsigned DiagID = isClassMessage ? diag::warn_class_method_not_found :
-                                       diag::warn_inst_method_not_found;
+    unsigned DiagID;
+    if (getLangOptions().ObjCAutoRefCount)
+      DiagID = diag::err_arc_method_not_found;
+    else
+      DiagID = isClassMessage ? diag::warn_class_method_not_found
+                              : diag::warn_inst_method_not_found;
     Diag(lbrac, DiagID)
       << Sel << isClassMessage << SourceRange(lbrac, rbrac);
     ReturnType = Context.getObjCIdType();
@@ -404,17 +432,15 @@
   return IsError;
 }
 
-bool Sema::isSelfExpr(Expr *RExpr) {
+bool Sema::isSelfExpr(Expr *receiver) {
   // 'self' is objc 'self' in an objc method only.
   DeclContext *DC = CurContext;
   while (isa<BlockDecl>(DC))
     DC = DC->getParent();
   if (DC && !isa<ObjCMethodDecl>(DC))
     return false;
-  if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(RExpr))
-    if (ICE->getCastKind() == CK_LValueToRValue)
-      RExpr = ICE->getSubExpr();
-  if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RExpr))
+  receiver = receiver->IgnoreParenLValueCasts();
+  if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(receiver))
     if (DRE->getDecl()->getIdentifier() == &Context.Idents.get("self"))
       return true;
   return false;
@@ -1013,11 +1039,16 @@
   // Find the method we are messaging.
   if (!Method) {
     if (Class->isForwardDecl()) {
+      if (getLangOptions().ObjCAutoRefCount) {
+        Diag(Loc, diag::err_arc_receiver_forward_class) << ReceiverType;
+      } else {
+        Diag(Loc, diag::warn_receiver_forward_class) << Class->getDeclName();
+      }
+
       // A forward class used in messaging is treated as a 'Class'
-      Diag(Loc, diag::warn_receiver_forward_class) << Class->getDeclName();
       Method = LookupFactoryMethodInGlobalPool(Sel, 
                                                SourceRange(LBracLoc, RBracLoc));
-      if (Method)
+      if (Method && !getLangOptions().ObjCAutoRefCount)
         Diag(Method->getLocation(), diag::note_method_sent_forward_class)
           << Method->getDeclName();
     }
@@ -1236,6 +1267,14 @@
                    = ReceiverType->getAsObjCInterfacePointerType()) {
         // We allow sending a message to a pointer to an interface (an object).
         ClassDecl = OCIType->getInterfaceDecl();
+
+        if (ClassDecl->isForwardDecl() && getLangOptions().ObjCAutoRefCount) {
+          Diag(Loc, diag::err_arc_receiver_forward_instance)
+            << OCIType->getPointeeType()
+            << (Receiver ? Receiver->getSourceRange() : SourceRange(SuperLoc));
+          return ExprError();
+        }
+
         // FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be
         // faster than the following method (which can do *many* linear searches).
         // The idea is to add class info to MethodPool.
@@ -1250,6 +1289,12 @@
           // If we have implementations in scope, check "private" methods.
           Method = LookupPrivateInstanceMethod(Sel, ClassDecl);
 
+          if (!Method && getLangOptions().ObjCAutoRefCount) {
+            Diag(Loc, diag::err_arc_may_not_respond)
+              << OCIType->getPointeeType() << Sel;
+            return ExprError();
+          }
+
           if (!Method && (!Receiver || !isSelfExpr(Receiver))) {
             // If we still haven't found a method, look in the global pool. This
             // behavior isn't very desirable, however we need it for GCC
@@ -1267,10 +1312,12 @@
         }
         if (Method && DiagnoseUseOfDecl(Method, Loc, forwardClass))
           return ExprError();
-      } else if (!Context.getObjCIdType().isNull() &&
+      } else if (!getLangOptions().ObjCAutoRefCount &&
+                 !Context.getObjCIdType().isNull() &&
                  (ReceiverType->isPointerType() || 
                   ReceiverType->isIntegerType())) {
         // Implicitly convert integers and pointers to 'id' but emit a warning.
+        // But not in ARC.
         Diag(Loc, diag::warn_bad_receiver_type)
           << ReceiverType 
           << Receiver->getSourceRange();
@@ -1332,8 +1379,37 @@
                           diag::err_illegal_message_expr_incomplete_type))
     return ExprError();
 
+  // In ARC, forbid the user from sending messages to 
+  // retain/release/autorelease/dealloc/retainCount explicitly.
+  if (getLangOptions().ObjCAutoRefCount) {
+    ObjCMethodFamily family =
+      (Method ? Method->getMethodFamily() : Sel.getMethodFamily());
+    switch (family) {
+    case OMF_init:
+      if (Method)
+        checkInitMethod(Method, ReceiverType);
+
+    case OMF_None:
+    case OMF_alloc:
+    case OMF_copy:
+    case OMF_mutableCopy:
+    case OMF_new:
+    case OMF_self:
+      break;
+
+    case OMF_dealloc:
+    case OMF_retain:
+    case OMF_release:
+    case OMF_autorelease:
+    case OMF_retainCount:
+      Diag(Loc, diag::err_arc_illegal_explicit_message)
+        << Sel << SelectorLoc;
+      break;
+    }
+  }
+
   // Construct the appropriate ObjCMessageExpr instance.
-  Expr *Result;
+  ObjCMessageExpr *Result;
   if (SuperLoc.isValid())
     Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
                                      SuperLoc,  /*IsInstanceSuper=*/true,
@@ -1343,6 +1419,27 @@
     Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
                                      Receiver, Sel, SelectorLoc, Method,
                                      Args, NumArgs, RBracLoc);
+
+  if (getLangOptions().ObjCAutoRefCount) {
+    // In ARC, annotate delegate init calls.
+    if (Result->getMethodFamily() == OMF_init &&
+        (SuperLoc.isValid() || isSelfExpr(Receiver))) {
+      // Only consider init calls *directly* in init implementations,
+      // not within blocks.
+      ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(CurContext);
+      if (method && method->getMethodFamily() == OMF_init) {
+        // The implicit assignment to self means we also don't want to
+        // consume the result.
+        Result->setDelegateInitCall(true);
+        return Owned(Result);
+      }
+    }
+
+    // In ARC, check for message sends which are likely to introduce
+    // retain cycles.
+    checkRetainCycles(Result);
+  }
+      
   return MaybeBindToTemporary(Result);
 }
 
@@ -1364,3 +1461,293 @@
                               LBracLoc, SelectorLoc, RBracLoc, move(Args));
 }
 
+enum ARCConversionTypeClass {
+  ACTC_none,
+  ACTC_retainable,
+  ACTC_indirectRetainable
+};
+static ARCConversionTypeClass classifyTypeForARCConversion(QualType type) {
+  ARCConversionTypeClass ACTC = ACTC_retainable;
+  
+  // Ignore an outermost reference type.
+  if (const ReferenceType *ref = type->getAs<ReferenceType>())
+    type = ref->getPointeeType();
+  
+  // Drill through pointers and arrays recursively.
+  while (true) {
+    if (const PointerType *ptr = type->getAs<PointerType>()) {
+      type = ptr->getPointeeType();
+    } else if (const ArrayType *array = type->getAsArrayTypeUnsafe()) {
+      type = QualType(array->getElementType()->getBaseElementTypeUnsafe(), 0);
+    } else {
+      break;
+    }
+    ACTC = ACTC_indirectRetainable;
+  }
+  
+  if (!type->isObjCRetainableType()) return ACTC_none;
+  return ACTC;
+}
+
+namespace {
+  /// Return true if the given expression can be reasonably converted
+  /// between a retainable pointer type and a C pointer type.
+  struct ARCCastChecker : StmtVisitor<ARCCastChecker, bool> {
+    ASTContext &Context;
+    ARCCastChecker(ASTContext &Context) : Context(Context) {}
+    bool VisitStmt(Stmt *s) {
+      return false;
+    }
+    bool VisitExpr(Expr *e) {
+      return e->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull);
+    }
+    
+    bool VisitParenExpr(ParenExpr *e) {
+      return Visit(e->getSubExpr());
+    }
+    bool VisitCastExpr(CastExpr *e) {
+      switch (e->getCastKind()) {
+        case CK_NullToPointer:
+          return true;
+        case CK_NoOp:
+        case CK_LValueToRValue:
+        case CK_BitCast:
+        case CK_AnyPointerToObjCPointerCast:
+        case CK_AnyPointerToBlockPointerCast:
+          return Visit(e->getSubExpr());
+        default:
+          return false;
+      }
+    }
+    bool VisitUnaryExtension(UnaryOperator *e) {
+      return Visit(e->getSubExpr());
+    }
+    bool VisitBinComma(BinaryOperator *e) {
+      return Visit(e->getRHS());
+    }
+    bool VisitConditionalOperator(ConditionalOperator *e) {
+      // Conditional operators are okay if both sides are okay.
+      return Visit(e->getTrueExpr()) && Visit(e->getFalseExpr());
+    }
+    bool VisitObjCStringLiteral(ObjCStringLiteral *e) {
+      // Always white-list Objective-C string literals.
+      return true;
+    }
+    bool VisitStmtExpr(StmtExpr *e) {
+      return Visit(e->getSubStmt()->body_back());
+    }
+    bool VisitDeclRefExpr(DeclRefExpr *e) {
+      // White-list references to global extern strings from system
+      // headers.
+      if (VarDecl *var = dyn_cast<VarDecl>(e->getDecl()))
+        if (var->getStorageClass() == SC_Extern &&
+            var->getType().isConstQualified() &&
+            Context.getSourceManager().isInSystemHeader(var->getLocation()))
+          return true;
+      return false;
+    }
+  };
+}
+
+void 
+Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
+                             Expr *castExpr, CheckedConversionKind CCK) {
+  QualType castExprType = castExpr->getType();
+  
+  ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExprType);
+  ARCConversionTypeClass castACTC = classifyTypeForARCConversion(castType);
+  if (exprACTC == castACTC) return;
+  if (exprACTC && castType->isBooleanType()) return;
+  
+  // Allow casts between pointers to lifetime types (e.g., __strong id*)
+  // and pointers to void (e.g., cv void *). Casting from void* to lifetime*
+  // must be explicit.
+  if (const PointerType *CastPtr = castType->getAs<PointerType>()) {
+    if (const PointerType *CastExprPtr = castExprType->getAs<PointerType>()) {
+      QualType CastPointee = CastPtr->getPointeeType();
+      QualType CastExprPointee = CastExprPtr->getPointeeType();
+      if ((CCK != CCK_ImplicitConversion && 
+           CastPointee->isObjCIndirectLifetimeType() && 
+           CastExprPointee->isVoidType()) ||
+          (CastPointee->isVoidType() && 
+           CastExprPointee->isObjCIndirectLifetimeType()))
+        return;
+    }
+  }
+  
+  if (ARCCastChecker(Context).Visit(castExpr))
+    return;
+  
+  SourceLocation loc =
+  (castRange.isValid() ? castRange.getBegin() : castExpr->getExprLoc());
+  
+  if (makeUnavailableInSystemHeader(loc,
+                                    "converts between Objective-C and C pointers in -fobjc-arc"))
+    return;
+  
+  unsigned srcKind;
+  switch (exprACTC) {
+    case ACTC_none:
+      srcKind = (castExprType->isPointerType() ? 1 : 0);
+      break;
+    case ACTC_retainable:
+      srcKind = (castExprType->isBlockPointerType() ? 2 : 3);
+      break;
+    case ACTC_indirectRetainable:
+      srcKind = 4;
+      break;
+  }
+  
+  if (CCK == CCK_CStyleCast) {
+    // Check whether this could be fixed with a bridge cast.
+    SourceLocation AfterLParen = PP.getLocForEndOfToken(castRange.getBegin());
+    SourceLocation NoteLoc = AfterLParen.isValid()? AfterLParen : loc;
+    
+    if (castType->isObjCARCBridgableType() && 
+        castExprType->isCARCBridgableType()) {
+      Diag(loc, diag::err_arc_cast_requires_bridge)
+        << 2
+        << castExprType
+        << (castType->isBlockPointerType()? 1 : 0)
+        << castType
+        << castRange
+        << castExpr->getSourceRange();
+      Diag(NoteLoc, diag::note_arc_bridge)
+        << FixItHint::CreateInsertion(AfterLParen, "__bridge ");
+      Diag(NoteLoc, diag::note_arc_bridge_transfer)
+        << castExprType
+        << FixItHint::CreateInsertion(AfterLParen, "__bridge_transfer ");
+      
+      return;
+    }
+    
+    if (castType->isCARCBridgableType() && 
+        castExprType->isObjCARCBridgableType()){
+      Diag(loc, diag::err_arc_cast_requires_bridge)
+        << (castExprType->isBlockPointerType()? 1 : 0)
+        << castExprType
+        << 2
+        << castType
+        << castRange
+        << castExpr->getSourceRange();
+
+      Diag(NoteLoc, diag::note_arc_bridge)
+        << FixItHint::CreateInsertion(AfterLParen, "__bridge ");
+      Diag(NoteLoc, diag::note_arc_bridge_retained)
+        << castType
+        << FixItHint::CreateInsertion(AfterLParen, "__bridge_retained ");
+      return;
+    }
+  }
+  
+  Diag(loc, diag::err_arc_mismatched_cast)
+    << (CCK != CCK_ImplicitConversion) << srcKind << castExprType << castType
+    << castRange << castExpr->getSourceRange();
+}
+
+ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc,
+                                      ObjCBridgeCastKind Kind,
+                                      SourceLocation BridgeKeywordLoc,
+                                      TypeSourceInfo *TSInfo,
+                                      Expr *SubExpr) {
+  QualType T = TSInfo->getType();
+  QualType FromType = SubExpr->getType();
+
+  bool MustConsume = false;
+  if (T->isDependentType() || SubExpr->isTypeDependent()) {
+    // Okay: we'll build a dependent expression type.
+  } else if (T->isObjCARCBridgableType() && FromType->isCARCBridgableType()) {
+    // Casting CF -> id
+    switch (Kind) {
+    case OBC_Bridge:
+      break;
+      
+    case OBC_BridgeRetained:
+      Diag(BridgeKeywordLoc, diag::err_arc_bridge_cast_wrong_kind)
+        << 2
+        << FromType
+        << (T->isBlockPointerType()? 1 : 0)
+        << T
+        << SubExpr->getSourceRange()
+        << Kind;
+      Diag(BridgeKeywordLoc, diag::note_arc_bridge)
+        << FixItHint::CreateReplacement(BridgeKeywordLoc, "__bridge");
+      Diag(BridgeKeywordLoc, diag::note_arc_bridge_transfer)
+        << FromType
+        << FixItHint::CreateReplacement(BridgeKeywordLoc, 
+                                        "__bridge_transfer ");
+
+      Kind = OBC_Bridge;
+      break;
+      
+    case OBC_BridgeTransfer:
+      // We must consume the Objective-C object produced by the cast.
+      MustConsume = true;
+      break;
+    }
+  } else if (T->isCARCBridgableType() && FromType->isObjCARCBridgableType()) {
+    // Okay: id -> CF
+    switch (Kind) {
+    case OBC_Bridge:
+      break;
+      
+    case OBC_BridgeRetained:        
+      // Produce the object before casting it.
+      SubExpr = ImplicitCastExpr::Create(Context, FromType,
+                                         CK_ObjCProduceObject,
+                                         SubExpr, 0, VK_RValue);
+      break;
+      
+    case OBC_BridgeTransfer:
+      Diag(BridgeKeywordLoc, diag::err_arc_bridge_cast_wrong_kind)
+        << (FromType->isBlockPointerType()? 1 : 0)
+        << FromType
+        << 2
+        << T
+        << SubExpr->getSourceRange()
+        << Kind;
+        
+      Diag(BridgeKeywordLoc, diag::note_arc_bridge)
+        << FixItHint::CreateReplacement(BridgeKeywordLoc, "__bridge ");
+      Diag(BridgeKeywordLoc, diag::note_arc_bridge_retained)
+        << T
+        << FixItHint::CreateReplacement(BridgeKeywordLoc, "__bridge_retained ");
+        
+      Kind = OBC_Bridge;
+      break;
+    }
+  } else {
+    Diag(LParenLoc, diag::err_arc_bridge_cast_incompatible)
+      << FromType << T << Kind
+      << SubExpr->getSourceRange()
+      << TSInfo->getTypeLoc().getSourceRange();
+    return ExprError();
+  }
+
+  Expr *Result = new (Context) ObjCBridgedCastExpr(LParenLoc, Kind, 
+                                                   BridgeKeywordLoc,
+                                                   TSInfo, SubExpr);
+  
+  if (MustConsume) {
+    ExprNeedsCleanups = true;
+    Result = ImplicitCastExpr::Create(Context, T, CK_ObjCConsumeObject, Result, 
+                                      0, VK_RValue);    
+  }
+  
+  return Result;
+}
+
+ExprResult Sema::ActOnObjCBridgedCast(Scope *S,
+                                      SourceLocation LParenLoc,
+                                      ObjCBridgeCastKind Kind,
+                                      SourceLocation BridgeKeywordLoc,
+                                      ParsedType Type,
+                                      SourceLocation RParenLoc,
+                                      Expr *SubExpr) {
+  TypeSourceInfo *TSInfo = 0;
+  QualType T = GetTypeFromParser(Type, &TSInfo);
+  if (!TSInfo)
+    TSInfo = Context.getTrivialTypeSourceInfo(T, LParenLoc);
+  return BuildObjCBridgedCast(LParenLoc, Kind, BridgeKeywordLoc, TSInfo, 
+                              SubExpr);
+}
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index a33f5d0..7793215 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -2029,10 +2029,10 @@
 
 DeclarationName InitializedEntity::getName() const {
   switch (getKind()) {
-  case EK_Parameter:
-    if (!VariableOrMember)
-      return DeclarationName();
-    // Fall through
+  case EK_Parameter: {
+    ParmVarDecl *D = reinterpret_cast<ParmVarDecl*>(Parameter & ~0x1);
+    return (D ? D->getDeclName() : DeclarationName());
+  }
 
   case EK_Variable:
   case EK_Member:
@@ -2057,10 +2057,12 @@
 DeclaratorDecl *InitializedEntity::getDecl() const {
   switch (getKind()) {
   case EK_Variable:
-  case EK_Parameter:
   case EK_Member:
     return VariableOrMember;
 
+  case EK_Parameter:
+    return reinterpret_cast<ParmVarDecl*>(Parameter & ~0x1);
+
   case EK_Result:
   case EK_Exception:
   case EK_New:
@@ -2123,6 +2125,9 @@
   case SK_StringInit:
   case SK_ObjCObjectConversion:
   case SK_ArrayInit:
+  case SK_PassByIndirectCopyRestore:
+  case SK_PassByIndirectRestore:
+  case SK_ProduceObjCObject:
     break;
 
   case SK_ConversionSequence:
@@ -2306,6 +2311,22 @@
   Steps.push_back(S);
 }
 
+void InitializationSequence::AddPassByIndirectCopyRestoreStep(QualType type,
+                                                              bool shouldCopy) {
+  Step s;
+  s.Kind = (shouldCopy ? SK_PassByIndirectCopyRestore
+                       : SK_PassByIndirectRestore);
+  s.Type = type;
+  Steps.push_back(s);
+}
+
+void InitializationSequence::AddProduceObjCObjectStep(QualType T) {
+  Step S;
+  S.Kind = SK_ProduceObjCObject;
+  S.Type = T;
+  Steps.push_back(S);
+}
+
 void InitializationSequence::SetOverloadFailure(FailureKind Failure,
                                                 OverloadingResult Result) {
   setSequenceKind(FailedSequence);
@@ -2317,6 +2338,33 @@
 // Attempt initialization
 //===----------------------------------------------------------------------===//
 
+static void MaybeProduceObjCObject(Sema &S,
+                                   InitializationSequence &Sequence,
+                                   const InitializedEntity &Entity) {
+  if (!S.getLangOptions().ObjCAutoRefCount) return;
+
+  /// When initializing a parameter, produce the value if it's marked
+  /// __attribute__((ns_consumed)).
+  if (Entity.getKind() == InitializedEntity::EK_Parameter) {
+    if (!Entity.isParameterConsumed())
+      return;
+
+    assert(Entity.getType()->isObjCRetainableType() &&
+           "consuming an object of unretainable type?");
+    Sequence.AddProduceObjCObjectStep(Entity.getType());
+
+  /// When initializing a return value, if the return type is a
+  /// retainable type, then returns need to immediately retain the
+  /// object.  If an autorelease is required, it will be done at the
+  /// last instant.
+  } else if (Entity.getKind() == InitializedEntity::EK_Result) {
+    if (!Entity.getType()->isObjCRetainableType())
+      return;
+
+    Sequence.AddProduceObjCObjectStep(Entity.getType());
+  }
+}
+
 /// \brief Attempt list initialization (C++0x [dcl.init.list])
 static void TryListInitialization(Sema &S,
                                   const InitializedEntity &Entity,
@@ -2380,13 +2428,16 @@
 
   bool DerivedToBase;
   bool ObjCConversion;
+  bool ObjCLifetimeConversion;
   assert(!S.CompareReferenceRelationship(Initializer->getLocStart(),
                                          T1, T2, DerivedToBase,
-                                         ObjCConversion) &&
+                                         ObjCConversion,
+                                         ObjCLifetimeConversion) &&
          "Must have incompatible references when binding via conversion");
   (void)DerivedToBase;
   (void)ObjCConversion;
-
+  (void)ObjCLifetimeConversion;
+  
   // Build the candidate set directly in the initialization sequence
   // structure, so that it will persist if we fail.
   OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
@@ -2513,10 +2564,12 @@
 
   bool NewDerivedToBase = false;
   bool NewObjCConversion = false;
+  bool NewObjCLifetimeConversion = false;
   Sema::ReferenceCompareResult NewRefRelationship
     = S.CompareReferenceRelationship(DeclLoc, T1,
                                      T2.getNonLValueExprType(S.Context),
-                                     NewDerivedToBase, NewObjCConversion);
+                                     NewDerivedToBase, NewObjCConversion,
+                                     NewObjCLifetimeConversion);
   if (NewRefRelationship == Sema::Ref_Incompatible) {
     // If the type we've converted to is not reference-related to the
     // type we're looking for, then there is another conversion step
@@ -2584,10 +2637,11 @@
   bool isRValueRef = !isLValueRef;
   bool DerivedToBase = false;
   bool ObjCConversion = false;
+  bool ObjCLifetimeConversion = false;
   Expr::Classification InitCategory = Initializer->Classify(S.Context);
   Sema::ReferenceCompareResult RefRelationship
     = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase,
-                                     ObjCConversion);
+                                     ObjCConversion, ObjCLifetimeConversion);
 
   // C++0x [dcl.init.ref]p5:
   //   A reference to type "cv1 T1" is initialized by an expression of type
@@ -2746,11 +2800,15 @@
 
   InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(cv1T1);
 
-  if (S.TryImplicitConversion(Sequence, TempEntity, Initializer,
+  ImplicitConversionSequence ICS
+    = S.TryImplicitConversion(Initializer, TempEntity.getType(),
                               /*SuppressUserConversions*/ false,
                               AllowExplicit,
                               /*FIXME:InOverloadResolution=*/false,
-                              /*CStyle=*/Kind.isCStyleOrFunctionalCast())) {
+                              /*CStyle=*/Kind.isCStyleOrFunctionalCast(),
+                              /*AllowObjCWritebackConversion=*/false);
+  
+  if (ICS.isBad()) {
     // FIXME: Use the conversion function set stored in ICS to turn
     // this into an overloading ambiguity diagnostic. However, we need
     // to keep that set as an OverloadCandidateSet rather than as some
@@ -2764,6 +2822,8 @@
     else
       Sequence.SetFailed(InitializationSequence::FK_ReferenceInitFailed);
     return;
+  } else {
+    Sequence.AddConversionSequenceStep(ICS, TempEntity.getType());
   }
 
   //        [...] If T1 is reference-related to T2, cv1 must be the
@@ -2953,10 +3013,8 @@
   // C++ [dcl.init]p6:
   //   To default-initialize an object of type T means:
   //     - if T is an array type, each element is default-initialized;
-  QualType DestType = Entity.getType();
-  while (const ArrayType *Array = S.Context.getAsArrayType(DestType))
-    DestType = Array->getElementType();
-
+  QualType DestType = S.Context.getBaseElementType(Entity.getType());
+         
   //     - if T is a (possibly cv-qualified) class type (Clause 9), the default
   //       constructor for T is called (and the initialization is ill-formed if
   //       T has no accessible default constructor);
@@ -2970,8 +3028,16 @@
   //   If a program calls for the default initialization of an object of
   //   a const-qualified type T, T shall be a class type with a user-provided
   //   default constructor.
-  if (DestType.isConstQualified() && S.getLangOptions().CPlusPlus)
+  if (DestType.isConstQualified() && S.getLangOptions().CPlusPlus) {
     Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
+    return;
+  }
+
+  // If the destination type has a lifetime property, zero-initialize it.
+  if (DestType.getQualifiers().hasObjCLifetime()) {
+    Sequence.AddZeroInitializationStep(Entity.getType());
+    return;
+  }
 }
 
 /// \brief Attempt a user-defined conversion between two types (C++ [dcl.init]),
@@ -3125,6 +3191,77 @@
   }
 }
 
+/// The non-zero enum values here are indexes into diagnostic alternatives.
+enum InvalidICRKind { IIK_okay, IIK_nonlocal, IIK_nonscalar };
+
+/// Determines whether this expression is an acceptable ICR source.
+static InvalidICRKind isInvalidICRSource(ASTContext &C, Expr *e) {
+  // Skip parens.
+  e = e->IgnoreParens();
+
+  // Skip address-of nodes.
+  if (UnaryOperator *op = dyn_cast<UnaryOperator>(e)) {
+    if (op->getOpcode() == UO_AddrOf)
+      return isInvalidICRSource(C, op->getSubExpr());
+
+  // Skip certain casts.
+  } else if (CastExpr *cast = dyn_cast<CastExpr>(e)) {
+    switch (cast->getCastKind()) {
+    case CK_Dependent:
+    case CK_BitCast:
+    case CK_LValueBitCast:
+    case CK_LValueToRValue:
+    case CK_NoOp:
+      return isInvalidICRSource(C, cast->getSubExpr());
+
+    case CK_ArrayToPointerDecay:
+      return IIK_nonscalar;
+
+    case CK_NullToPointer:
+      return IIK_okay;
+
+    default:
+      break;
+    }
+
+  // If we have a declaration reference, it had better be a local variable.
+  } else if (DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(e)) {
+    if (VarDecl *var = dyn_cast<VarDecl>(declRef->getDecl()))
+      return (var->hasLocalStorage() ? IIK_okay : IIK_nonlocal);
+
+  // If we have a conditional operator, check both sides.
+  } else if (ConditionalOperator *cond = dyn_cast<ConditionalOperator>(e)) {
+    if (InvalidICRKind iik = isInvalidICRSource(C, cond->getLHS()))
+      return iik;
+
+    return isInvalidICRSource(C, cond->getRHS());
+
+  // These are never scalar.
+  } else if (isa<ArraySubscriptExpr>(e)) {
+    return IIK_nonscalar;
+
+  // Otherwise, it needs to be a null pointer constant.
+  } else {
+    return (e->isNullPointerConstant(C, Expr::NPC_ValueDependentIsNull)
+            ? IIK_okay : IIK_nonlocal);
+  }
+
+  return IIK_nonlocal;
+}
+
+/// Check whether the given expression is a valid operand for an
+/// indirect copy/restore.
+static void checkIndirectCopyRestoreSource(Sema &S, Expr *src) {
+  assert(src->isRValue());
+
+  InvalidICRKind iik = isInvalidICRSource(S.Context, src);
+  if (iik == IIK_okay) return;
+
+  S.Diag(src->getExprLoc(), diag::err_arc_nonlocal_writeback)
+    << ((unsigned) iik - 1)  // shift index into diagnostic explanations
+    << src->getSourceRange();
+}
+
 /// \brief Determine whether we have compatible array types for the
 /// purposes of GNU by-copy array initialization.
 static bool hasCompatibleArrayTypes(ASTContext &Context,
@@ -3144,6 +3281,53 @@
   return Source->isConstantArrayType() && Dest->isIncompleteArrayType();
 }
 
+static bool tryObjCWritebackConversion(Sema &S,
+                                       InitializationSequence &Sequence,
+                                       const InitializedEntity &Entity,
+                                       Expr *Initializer) {
+  bool ArrayDecay = false;
+  QualType ArgType = Initializer->getType();
+  QualType ArgPointee;
+  if (const ArrayType *ArgArrayType = S.Context.getAsArrayType(ArgType)) {
+    ArrayDecay = true;
+    ArgPointee = ArgArrayType->getElementType();
+    ArgType = S.Context.getPointerType(ArgPointee);
+  }
+      
+  // Handle write-back conversion.
+  QualType ConvertedArgType;
+  if (!S.isObjCWritebackConversion(ArgType, Entity.getType(),
+                                   ConvertedArgType))
+    return false;
+
+  // We should copy unless we're passing to an argument explicitly
+  // marked 'out'.
+  bool ShouldCopy = true;
+  if (ParmVarDecl *param = cast_or_null<ParmVarDecl>(Entity.getDecl()))
+    ShouldCopy = (param->getObjCDeclQualifier() != ParmVarDecl::OBJC_TQ_Out);
+
+  // Do we need an lvalue conversion?
+  if (ArrayDecay || Initializer->isGLValue()) {
+    ImplicitConversionSequence ICS;
+    ICS.setStandard();
+    ICS.Standard.setAsIdentityConversion();
+
+    QualType ResultType;
+    if (ArrayDecay) {
+      ICS.Standard.First = ICK_Array_To_Pointer;
+      ResultType = S.Context.getPointerType(ArgPointee);
+    } else {
+      ICS.Standard.First = ICK_Lvalue_To_Rvalue;
+      ResultType = Initializer->getType().getNonLValueExprType(S.Context);
+    }
+          
+    Sequence.AddConversionSequenceStep(ICS, ResultType);
+  }
+        
+  Sequence.AddPassByIndirectCopyRestoreStep(Entity.getType(), ShouldCopy);
+  return true;
+}
+
 InitializationSequence::InitializationSequence(Sema &S,
                                                const InitializedEntity &Entity,
                                                const InitializationKind &Kind,
@@ -3255,12 +3439,28 @@
     return;
   }
 
-  // Handle initialization in C
+  // Determine whether we should consider writeback conversions for 
+  // Objective-C ARC.
+  bool allowObjCWritebackConversion = S.getLangOptions().ObjCAutoRefCount &&
+    Entity.getKind() == InitializedEntity::EK_Parameter;
+
+  // We're at the end of the line for C: it's either a write-back conversion
+  // or it's a C assignment. There's no need to check anything else.
   if (!S.getLangOptions().CPlusPlus) {
+    // If allowed, check whether this is an Objective-C writeback conversion.
+    if (allowObjCWritebackConversion &&
+        tryObjCWritebackConversion(S, *this, Entity, Initializer)) {
+      return;
+    }
+    
+    // Handle initialization in C
     AddCAssignmentStep(DestType);
+    MaybeProduceObjCObject(S, *this, Entity);
     return;
   }
 
+  assert(S.getLangOptions().CPlusPlus);
+      
   //     - If the destination type is a (possibly cv-qualified) class type:
   if (DestType->isRecordType()) {
     //     - If the initialization is direct-initialization, or if it is
@@ -3294,6 +3494,7 @@
   //      type, conversion functions are considered.
   if (!SourceType.isNull() && SourceType->isRecordType()) {
     TryUserDefinedConversion(S, Entity, Kind, Initializer, *this);
+    MaybeProduceObjCObject(S, *this, Entity);
     return;
   }
 
@@ -3302,12 +3503,38 @@
   //      conversions (Clause 4) will be used, if necessary, to convert the
   //      initializer expression to the cv-unqualified version of the
   //      destination type; no user-defined conversions are considered.
-  if (S.TryImplicitConversion(*this, Entity, Initializer,
-                              /*SuppressUserConversions*/ true,
+      
+  ImplicitConversionSequence ICS
+    = S.TryImplicitConversion(Initializer, Entity.getType(),
+                              /*SuppressUserConversions*/true,
                               /*AllowExplicitConversions*/ false,
                               /*InOverloadResolution*/ false,
-                              /*CStyle=*/Kind.isCStyleOrFunctionalCast()))
-  {
+                              /*CStyle=*/Kind.isCStyleOrFunctionalCast(),
+                              allowObjCWritebackConversion);
+      
+  if (ICS.isStandard() && 
+      ICS.Standard.Second == ICK_Writeback_Conversion) {
+    // Objective-C ARC writeback conversion.
+    
+    // We should copy unless we're passing to an argument explicitly
+    // marked 'out'.
+    bool ShouldCopy = true;
+    if (ParmVarDecl *Param = cast_or_null<ParmVarDecl>(Entity.getDecl()))
+      ShouldCopy = (Param->getObjCDeclQualifier() != ParmVarDecl::OBJC_TQ_Out);
+    
+    // If there was an lvalue adjustment, add it as a separate conversion.
+    if (ICS.Standard.First == ICK_Array_To_Pointer ||
+        ICS.Standard.First == ICK_Lvalue_To_Rvalue) {
+      ImplicitConversionSequence LvalueICS;
+      LvalueICS.setStandard();
+      LvalueICS.Standard.setAsIdentityConversion();
+      LvalueICS.Standard.setAllToTypes(ICS.Standard.getToType(0));
+      LvalueICS.Standard.First = ICS.Standard.First;
+      AddConversionSequenceStep(LvalueICS, ICS.Standard.getToType(0));
+    }
+    
+    AddPassByIndirectCopyRestoreStep(Entity.getType(), ShouldCopy);
+  } else if (ICS.isBad()) {
     DeclAccessPair dap;
     if (Initializer->getType() == Context.OverloadTy && 
           !S.ResolveAddressOfOverloadedFunction(Initializer
@@ -3315,6 +3542,8 @@
       SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
     else
       SetFailed(InitializationSequence::FK_ConversionFailed);
+  } else {
+    AddConversionSequenceStep(ICS, Entity.getType());
   }
 }
 
@@ -3560,7 +3789,7 @@
       << (int)Entity.getKind() << CurInitExpr->getType()
       << CurInitExpr->getSourceRange();
     S.Diag(Best->Function->getLocation(), diag::note_unavailable_here)
-      << Best->Function->isDeleted();
+      << 1 << Best->Function->isDeleted();
     return ExprError();
   }
 
@@ -3733,7 +3962,10 @@
   case SK_CAssignment:
   case SK_StringInit:
   case SK_ObjCObjectConversion:
-  case SK_ArrayInit: {
+  case SK_ArrayInit:
+  case SK_PassByIndirectCopyRestore:
+  case SK_PassByIndirectRestore:
+  case SK_ProduceObjCObject: {
     assert(Args.size() == 1);
     CurInit = Args.get()[0];
     if (!CurInit.get()) return ExprError();
@@ -3969,10 +4201,14 @@
     }
 
     case SK_ConversionSequence: {
+      Sema::CheckedConversionKind CCK 
+        = Kind.isCStyleCast()? Sema::CCK_CStyleCast
+        : Kind.isFunctionalCast()? Sema::CCK_FunctionalCast
+        : Kind.isExplicitCast()? Sema::CCK_OtherCast
+        : Sema::CCK_ImplicitConversion;
       ExprResult CurInitExprRes =
         S.PerformImplicitConversion(CurInit.get(), Step->Type, *Step->ICS,
-                                    getAssignmentAction(Entity),
-                                    Kind.isCStyleOrFunctionalCast());
+                                    getAssignmentAction(Entity), CCK);
       if (CurInitExprRes.isInvalid())
         return ExprError();
       CurInit = move(CurInitExprRes);
@@ -4182,7 +4418,20 @@
           }
         }
       }
+      break;
 
+    case SK_PassByIndirectCopyRestore:
+    case SK_PassByIndirectRestore:
+      checkIndirectCopyRestoreSource(S, CurInit.get());
+      CurInit = S.Owned(new (S.Context)
+                        ObjCIndirectCopyRestoreExpr(CurInit.take(), Step->Type,
+                                Step->Kind == SK_PassByIndirectCopyRestore));
+      break;
+
+    case SK_ProduceObjCObject:
+      CurInit = S.Owned(ImplicitCastExpr::Create(S.Context, Step->Type,
+                                                 CK_ObjCProduceObject,
+                                                 CurInit.take(), 0, VK_RValue));
       break;
     }
   }
@@ -4278,7 +4527,7 @@
                                                 true);
       if (Ovl == OR_Deleted) {
         S.Diag(Best->Function->getLocation(), diag::note_unavailable_here)
-          << Best->Function->isDeleted();
+          << 1 << Best->Function->isDeleted();
       } else {
         llvm_unreachable("Inconsistent overload resolution?");
       }
@@ -4443,7 +4692,7 @@
           = FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best);
         if (Ovl == OR_Deleted) {
           S.Diag(Best->Function->getLocation(), diag::note_unavailable_here)
-            << Best->Function->isDeleted();
+            << 1 << Best->Function->isDeleted();
         } else {
           llvm_unreachable("Inconsistent overload resolution?");
         }
@@ -4674,6 +4923,18 @@
     case SK_ArrayInit:
       OS << "array initialization";
       break;
+
+    case SK_PassByIndirectCopyRestore:
+      OS << "pass by indirect copy and restore";
+      break;
+
+    case SK_PassByIndirectRestore:
+      OS << "pass by indirect restore";
+      break;
+
+    case SK_ProduceObjCObject:
+      OS << "Objective-C object retension";
+      break;
     }
   }
 }
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index 6c4469c..2dbb740 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -24,6 +24,51 @@
 // Grammar actions.
 //===----------------------------------------------------------------------===//
 
+/// Check the internal consistency of a property declaration.
+static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) {
+  if (property->isInvalidDecl()) return;
+
+  ObjCPropertyDecl::PropertyAttributeKind propertyKind
+    = property->getPropertyAttributes();
+  Qualifiers::ObjCLifetime propertyLifetime
+    = property->getType().getObjCLifetime();
+
+  // Nothing to do if we don't have a lifetime.
+  if (propertyLifetime == Qualifiers::OCL_None) return;
+
+  Qualifiers::ObjCLifetime expectedLifetime;
+  unsigned selector;
+
+  // Strong properties should have either strong or no lifetime.
+  if (propertyKind & (ObjCPropertyDecl::OBJC_PR_retain |
+                      ObjCPropertyDecl::OBJC_PR_strong |
+                      ObjCPropertyDecl::OBJC_PR_copy)) {
+    expectedLifetime = Qualifiers::OCL_Strong;
+    selector = 0;
+  } else if (propertyKind & ObjCPropertyDecl::OBJC_PR_weak) {
+    expectedLifetime = Qualifiers::OCL_Weak;
+    selector = 1;
+  } else if (propertyKind & (ObjCPropertyDecl::OBJC_PR_assign |
+                             ObjCPropertyDecl::OBJC_PR_unsafe_unretained) &&
+             property->getType()->isObjCRetainableType()) {
+    expectedLifetime = Qualifiers::OCL_ExplicitNone;
+    selector = 2;
+  } else {
+    // We have a lifetime qualifier but no dominating property
+    // attribute.  That's okay.
+    return;
+  }
+
+  if (propertyLifetime == expectedLifetime) return;
+
+  property->setInvalidDecl();
+  S.Diag(property->getLocation(),
+         diag::err_arc_inconsistent_property_lifetime)
+    << property->getDeclName()
+    << selector
+    << propertyLifetime;
+}
+
 Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
                           FieldDeclarator &FD,
                           ObjCDeclSpec &ODS,
@@ -34,6 +79,14 @@
                           tok::ObjCKeywordKind MethodImplKind,
                           DeclContext *lexicalDC) {
   unsigned Attributes = ODS.getPropertyAttributes();
+  TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S);
+  QualType T = TSI->getType();
+  if ((getLangOptions().getGCMode() != LangOptions::NonGC && 
+       T.isObjCGCWeak()) ||
+      (getLangOptions().ObjCAutoRefCount &&
+       T.getObjCLifetime() == Qualifiers::OCL_Weak))
+    Attributes |= ObjCDeclSpec::DQ_PR_weak;
+
   bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) ||
                       // default is readwrite!
                       !(Attributes & ObjCDeclSpec::DQ_PR_readonly));
@@ -42,9 +95,10 @@
   bool isAssign = ((Attributes & ObjCDeclSpec::DQ_PR_assign) ||
                    (isReadWrite &&
                     !(Attributes & ObjCDeclSpec::DQ_PR_retain) &&
-                    !(Attributes & ObjCDeclSpec::DQ_PR_copy)));
-
-  TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S);
+                    !(Attributes & ObjCDeclSpec::DQ_PR_strong) &&
+                    !(Attributes & ObjCDeclSpec::DQ_PR_copy) &&
+                    !(Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) &&
+                    !(Attributes & ObjCDeclSpec::DQ_PR_weak)));
 
   // Proceed with constructing the ObjCPropertDecls.
   ObjCContainerDecl *ClassDecl =
@@ -58,20 +112,27 @@
                                            Attributes,
                                            isOverridingProperty, TSI,
                                            MethodImplKind);
-      if (Res)
+      if (Res) {
         CheckObjCPropertyAttributes(Res, AtLoc, Attributes);
+        if (getLangOptions().ObjCAutoRefCount)
+          checkARCPropertyDecl(*this, cast<ObjCPropertyDecl>(Res));
+      }
       return Res;
     }
   
-  Decl *Res = CreatePropertyDecl(S, ClassDecl, AtLoc, FD,
-                                 GetterSel, SetterSel,
-                                 isAssign, isReadWrite,
-                                 Attributes, TSI, MethodImplKind);
+  ObjCPropertyDecl *Res = CreatePropertyDecl(S, ClassDecl, AtLoc, FD,
+                                             GetterSel, SetterSel,
+                                             isAssign, isReadWrite,
+                                             Attributes, TSI, MethodImplKind);
   if (lexicalDC)
     Res->setLexicalDeclContext(lexicalDC);
 
   // Validate the attributes on the @property.
   CheckObjCPropertyAttributes(Res, AtLoc, Attributes);
+
+  if (getLangOptions().ObjCAutoRefCount)
+    checkARCPropertyDecl(*this, Res);
+
   return Res;
 }
 
@@ -158,6 +219,7 @@
   if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) {
     unsigned retainCopyNonatomic =
     (ObjCPropertyDecl::OBJC_PR_retain |
+     ObjCPropertyDecl::OBJC_PR_strong |
      ObjCPropertyDecl::OBJC_PR_copy |
      ObjCPropertyDecl::OBJC_PR_nonatomic);
     if ((Attributes & retainCopyNonatomic) !=
@@ -189,6 +251,8 @@
     PIDecl->makeitReadWriteAttribute();
     if (Attributes & ObjCDeclSpec::DQ_PR_retain)
       PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
+    if (Attributes & ObjCDeclSpec::DQ_PR_strong)
+      PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
     if (Attributes & ObjCDeclSpec::DQ_PR_copy)
       PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
     PIDecl->setSetterName(SetterSel);
@@ -287,9 +351,18 @@
   if (Attributes & ObjCDeclSpec::DQ_PR_retain)
     PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
 
+  if (Attributes & ObjCDeclSpec::DQ_PR_strong)
+    PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
+
+  if (Attributes & ObjCDeclSpec::DQ_PR_weak)
+    PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_weak);
+
   if (Attributes & ObjCDeclSpec::DQ_PR_copy)
     PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
 
+  if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained)
+    PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
+
   if (isAssign)
     PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign);
 
@@ -298,8 +371,17 @@
   else if (Attributes & ObjCDeclSpec::DQ_PR_atomic)
     PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_atomic);
 
+  // FIXME: Why do PropertyAttributesAsWritten get set from PropertyAttributes,
+  // shouldn't PropertyAttributesAsWritten get set *only* through the attributes
+  // of the ObjCDeclSpec ?
   PDecl->setPropertyAttributesAsWritten(PDecl->getPropertyAttributes());
-  
+
+  // 'unsafe_unretained' is alias for 'assign'.
+  if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained)
+    PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign);
+  if (isAssign)
+    PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
+
   if (MethodImplKind == tok::objc_required)
     PDecl->setPropertyImplementation(ObjCPropertyDecl::Required);
   else if (MethodImplKind == tok::objc_optional)
@@ -308,6 +390,93 @@
   return PDecl;
 }
 
+static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc,
+                                 ObjCPropertyDecl *property,
+                                 ObjCIvarDecl *ivar) {
+  if (property->isInvalidDecl() || ivar->isInvalidDecl()) return;
+
+  QualType propertyType = property->getType();
+  Qualifiers::ObjCLifetime propertyLifetime = propertyType.getObjCLifetime();
+  ObjCPropertyDecl::PropertyAttributeKind propertyKind
+    = property->getPropertyAttributes();
+
+  QualType ivarType = ivar->getType();
+  Qualifiers::ObjCLifetime ivarLifetime = ivarType.getObjCLifetime();
+          
+  // Case 1: strong properties.
+  if (propertyLifetime == Qualifiers::OCL_Strong ||
+      (propertyKind & (ObjCPropertyDecl::OBJC_PR_retain |
+                       ObjCPropertyDecl::OBJC_PR_strong |
+                       ObjCPropertyDecl::OBJC_PR_copy))) {
+    switch (ivarLifetime) {
+    case Qualifiers::OCL_Strong:
+      // Okay.
+      return;
+
+    case Qualifiers::OCL_None:
+    case Qualifiers::OCL_Autoreleasing:
+      // These aren't valid lifetimes for object ivars;  don't diagnose twice.
+      return;
+
+    case Qualifiers::OCL_ExplicitNone:
+    case Qualifiers::OCL_Weak:
+      S.Diag(propertyImplLoc, diag::err_arc_strong_property_lifetime)
+        << property->getDeclName()
+        << ivar->getDeclName()
+        << ivarLifetime;
+      break;
+    }
+
+  // Case 2: weak properties.
+  } else if (propertyLifetime == Qualifiers::OCL_Weak ||
+             (propertyKind & ObjCPropertyDecl::OBJC_PR_weak)) {
+    switch (ivarLifetime) {
+    case Qualifiers::OCL_Weak:
+      // Okay.
+      return;
+
+    case Qualifiers::OCL_None:
+    case Qualifiers::OCL_Autoreleasing:
+      // These aren't valid lifetimes for object ivars;  don't diagnose twice.
+      return;
+
+    case Qualifiers::OCL_ExplicitNone:
+    case Qualifiers::OCL_Strong:
+      S.Diag(propertyImplLoc, diag::error_weak_property)
+        << property->getDeclName()
+        << ivar->getDeclName();
+      break;
+    }
+
+  // Case 3: assign properties.
+  } else if ((propertyKind & ObjCPropertyDecl::OBJC_PR_assign) &&
+             propertyType->isObjCRetainableType()) {
+    switch (ivarLifetime) {
+    case Qualifiers::OCL_ExplicitNone:
+      // Okay.
+      return;
+
+    case Qualifiers::OCL_None:
+    case Qualifiers::OCL_Autoreleasing:
+      // These aren't valid lifetimes for object ivars;  don't diagnose twice.
+      return;
+
+    case Qualifiers::OCL_Weak:
+    case Qualifiers::OCL_Strong:
+      S.Diag(propertyImplLoc, diag::err_arc_assign_property_lifetime)
+        << property->getDeclName()
+        << ivar->getDeclName();
+      break;
+    }
+
+  // Any other property should be ignored.
+  } else {
+    return;
+  }
+
+  S.Diag(property->getLocation(), diag::note_property_declare);
+}
+
 
 /// ActOnPropertyImplDecl - This routine performs semantic checks and
 /// builds the AST node for a property implementation declaration; declared
@@ -399,6 +568,8 @@
     // @synthesize
     if (!PropertyIvar)
       PropertyIvar = PropertyId;
+    ObjCPropertyDecl::PropertyAttributeKind kind 
+      = property->getPropertyAttributes();
     QualType PropType = Context.getCanonicalType(property->getType());
     QualType PropertyIvarType = PropType;
     if (PropType->isReferenceType())
@@ -407,6 +578,45 @@
     ObjCInterfaceDecl *ClassDeclared;
     Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared);
     if (!Ivar) {
+      // In ARC, give the ivar a lifetime qualifier based on its
+      // property attributes.
+      if (getLangOptions().ObjCAutoRefCount &&
+          !PropertyIvarType.getObjCLifetime()) {
+
+        // retain/copy have retaining lifetime.
+        if (kind & (ObjCPropertyDecl::OBJC_PR_retain |
+                    ObjCPropertyDecl::OBJC_PR_strong |
+                    ObjCPropertyDecl::OBJC_PR_copy)) {
+          Qualifiers qs;
+          qs.addObjCLifetime(Qualifiers::OCL_Strong);
+          PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs);
+        }
+        else if (kind & ObjCPropertyDecl::OBJC_PR_weak) {
+          if (getLangOptions().ObjCNoAutoRefCountRuntime) {
+            Diag(PropertyLoc, diag::err_arc_weak_no_runtime);
+            Diag(property->getLocation(), diag::note_property_declare);
+          }
+          Qualifiers qs;
+          qs.addObjCLifetime(Qualifiers::OCL_Weak);
+          PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs);   
+        }
+        else if (kind & ObjCPropertyDecl::OBJC_PR_assign &&
+                 PropertyIvarType->isObjCRetainableType()) {
+            // assume that an 'assign' property synthesizes __unsafe_unretained
+            // ivar
+            Qualifiers qs;
+            qs.addObjCLifetime(Qualifiers::OCL_ExplicitNone);
+            PropertyIvarType = Context.getQualifiedType(PropertyIvarType, qs);  
+        }
+      }
+
+      if (kind & ObjCPropertyDecl::OBJC_PR_weak &&
+          !getLangOptions().ObjCAutoRefCount &&
+          getLangOptions().getGCMode() == LangOptions::NonGC) {
+        Diag(PropertyLoc, diag::error_synthesize_weak_non_arc_or_gc);
+        Diag(property->getLocation(), diag::note_property_declare);
+      }
+
       Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl,
                                   PropertyLoc, PropertyLoc, PropertyIvar,
                                   PropertyIvarType, /*Dinfo=*/0,
@@ -435,7 +645,7 @@
     if (PropertyIvarType != IvarType) {
       bool compat = false;
       if (isa<ObjCObjectPointerType>(PropertyIvarType) 
-            && isa<ObjCObjectPointerType>(IvarType))
+          && isa<ObjCObjectPointerType>(IvarType))
         compat = 
           Context.canAssignObjCInterfaces(
                                   PropertyIvarType->getAs<ObjCObjectPointerType>(),
@@ -470,12 +680,13 @@
         // Fall thru - see previous comment
       }
       // __weak is explicit. So it works on Canonical type.
-      if (PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() &&
-          getLangOptions().getGCMode() != LangOptions::NonGC) {
+      if ((PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() &&
+           getLangOptions().getGCMode() != LangOptions::NonGC)) {
         Diag(PropertyLoc, diag::error_weak_property)
         << property->getDeclName() << Ivar->getDeclName();
         // Fall thru - see previous comment
       }
+      // Fall thru - see previous comment
       if ((property->getType()->isObjCObjectPointerType() ||
            PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() &&
           getLangOptions().getGCMode() != LangOptions::NonGC) {
@@ -484,9 +695,12 @@
         // Fall thru - see previous comment
       }
     }
+    if (getLangOptions().ObjCAutoRefCount)
+      checkARCPropertyImpl(*this, PropertyLoc, property, Ivar);
   } else if (PropertyIvar)
     // @dynamic
     Diag(PropertyLoc, diag::error_dynamic_property_ivar_decl);
+    
   assert (property && "ActOnPropertyImplDecl - property declaration missing");
   ObjCPropertyImplDecl *PIDecl =
   ObjCPropertyImplDecl::Create(Context, CurContext, AtLoc, PropertyLoc,
@@ -632,10 +846,19 @@
       != (SAttr & ObjCPropertyDecl::OBJC_PR_copy))
     Diag(Property->getLocation(), diag::warn_property_attribute)
       << Property->getDeclName() << "copy" << inheritedName;
-  else if ((CAttr & ObjCPropertyDecl::OBJC_PR_retain)
-           != (SAttr & ObjCPropertyDecl::OBJC_PR_retain))
-    Diag(Property->getLocation(), diag::warn_property_attribute)
-      << Property->getDeclName() << "retain" << inheritedName;
+  else {
+    unsigned CAttrRetain = 
+      (CAttr & 
+       (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_strong));
+    unsigned SAttrRetain = 
+      (SAttr & 
+       (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_strong));
+    bool CStrong = (CAttrRetain != 0);
+    bool SStrong = (SAttrRetain != 0);
+    if (CStrong != SStrong)
+      Diag(Property->getLocation(), diag::warn_property_attribute)
+        << Property->getDeclName() << "retain (or strong)" << inheritedName;
+  }
 
   if ((CAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)
       != (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic))
@@ -1135,6 +1358,34 @@
   }
 }
 
+void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D) {
+  if (getLangOptions().getGCMode() == LangOptions::GCOnly)
+    return;
+
+  for (ObjCImplementationDecl::propimpl_iterator
+         i = D->propimpl_begin(), e = D->propimpl_end(); i != e; ++i) {
+    ObjCPropertyImplDecl *PID = *i;
+    if (PID->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
+      continue;
+    
+    const ObjCPropertyDecl *PD = PID->getPropertyDecl();
+    if (PD && !D->getInstanceMethod(PD->getGetterName())) {
+      ObjCMethodDecl *method = PD->getGetterMethodDecl();
+      if (!method)
+        continue;
+      ObjCMethodFamily family = method->getMethodFamily();
+      if (family == OMF_alloc || family == OMF_copy ||
+          family == OMF_mutableCopy || family == OMF_new) {
+        if (getLangOptions().ObjCAutoRefCount)
+          Diag(PID->getLocation(), diag::err_ownin_getter_rule);
+        else
+          Diag(PID->getLocation(), diag::warn_ownin_getter_rule);
+        Diag(PD->getLocation(), diag::note_property_declare);
+      }
+    }
+  }
+}
+
 /// AddPropertyAttrs - Propagates attributes from a property to the
 /// implicitly-declared getter or setter for that property.
 static void AddPropertyAttrs(Sema &S, ObjCMethodDecl *PropertyMethod,
@@ -1245,7 +1496,7 @@
       ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod,
                                                   Loc, Loc,
                                                   property->getIdentifier(),
-                                                  property->getType(),
+                                    property->getType().getUnqualifiedType(),
                                                   /*TInfo=*/0,
                                                   SC_None,
                                                   SC_None,
@@ -1287,7 +1538,7 @@
                                        SourceLocation Loc,
                                        unsigned &Attributes) {
   // FIXME: Improve the reported location.
-  if (!PDecl)
+  if (!PDecl || PDecl->isInvalidDecl())
     return;
 
   ObjCPropertyDecl *PropertyDecl = cast<ObjCPropertyDecl>(PDecl);
@@ -1297,12 +1548,16 @@
   if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
       (Attributes & (ObjCDeclSpec::DQ_PR_readwrite |
                      ObjCDeclSpec::DQ_PR_assign |
+                     ObjCDeclSpec::DQ_PR_unsafe_unretained |
                      ObjCDeclSpec::DQ_PR_copy |
-                     ObjCDeclSpec::DQ_PR_retain))) {
+                     ObjCDeclSpec::DQ_PR_retain |
+                     ObjCDeclSpec::DQ_PR_strong))) {
     const char * which = (Attributes & ObjCDeclSpec::DQ_PR_readwrite) ?
                           "readwrite" :
                          (Attributes & ObjCDeclSpec::DQ_PR_assign) ?
                           "assign" :
+                         (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) ?
+                          "unsafe_unretained" :
                          (Attributes & ObjCDeclSpec::DQ_PR_copy) ?
                           "copy" : "retain";
 
@@ -1313,14 +1568,15 @@
   }
 
   // Check for copy or retain on non-object types.
-  if ((Attributes & (ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain)) &&
-      !PropertyTy->isObjCObjectPointerType() &&
-      !PropertyTy->isBlockPointerType() &&
-      !Context.isObjCNSObjectType(PropertyTy) &&
+  if ((Attributes & (ObjCDeclSpec::DQ_PR_weak | ObjCDeclSpec::DQ_PR_copy |
+                    ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong)) &&
+      !PropertyTy->isObjCRetainableType() &&
       !PropertyDecl->getAttr<ObjCNSObjectAttr>()) {
     Diag(Loc, diag::err_objc_property_requires_object)
-      << (Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain");
-    Attributes &= ~(ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain);
+      << (Attributes & ObjCDeclSpec::DQ_PR_weak ? "weak" :
+          Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain (or strong)");
+    Attributes &= ~(ObjCDeclSpec::DQ_PR_weak   | ObjCDeclSpec::DQ_PR_copy |
+                    ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong);
   }
 
   // Check for more than one of { assign, copy, retain }.
@@ -1335,27 +1591,88 @@
         << "assign" << "retain";
       Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
     }
+    if (Attributes & ObjCDeclSpec::DQ_PR_strong) {
+      Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+        << "assign" << "strong";
+      Attributes &= ~ObjCDeclSpec::DQ_PR_strong;
+    }
+    if (getLangOptions().ObjCAutoRefCount  &&
+        (Attributes & ObjCDeclSpec::DQ_PR_weak)) {
+      Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+        << "assign" << "weak";
+      Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
+    }
+  } else if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) {
+    if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
+      Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+        << "unsafe_unretained" << "copy";
+      Attributes &= ~ObjCDeclSpec::DQ_PR_copy;
+    }
+    if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
+      Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+        << "unsafe_unretained" << "retain";
+      Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
+    }
+    if (Attributes & ObjCDeclSpec::DQ_PR_strong) {
+      Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+        << "unsafe_unretained" << "strong";
+      Attributes &= ~ObjCDeclSpec::DQ_PR_strong;
+    }
+    if (getLangOptions().ObjCAutoRefCount  &&
+        (Attributes & ObjCDeclSpec::DQ_PR_weak)) {
+      Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+        << "unsafe_unretained" << "weak";
+      Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
+    }
   } else if (Attributes & ObjCDeclSpec::DQ_PR_copy) {
     if (Attributes & ObjCDeclSpec::DQ_PR_retain) {
       Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
         << "copy" << "retain";
       Attributes &= ~ObjCDeclSpec::DQ_PR_retain;
     }
+    if (Attributes & ObjCDeclSpec::DQ_PR_strong) {
+      Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+        << "copy" << "strong";
+      Attributes &= ~ObjCDeclSpec::DQ_PR_strong;
+    }
+    if (Attributes & ObjCDeclSpec::DQ_PR_weak) {
+      Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+        << "copy" << "weak";
+      Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
+    }
+  }
+  else if ((Attributes & ObjCDeclSpec::DQ_PR_retain) &&
+           (Attributes & ObjCDeclSpec::DQ_PR_weak)) {
+      Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+        << "retain" << "weak";
+      Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
+  }
+  else if ((Attributes & ObjCDeclSpec::DQ_PR_strong) &&
+           (Attributes & ObjCDeclSpec::DQ_PR_weak)) {
+      Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+        << "strong" << "weak";
+      Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
   }
 
   // Warn if user supplied no assignment attribute, property is
   // readwrite, and this is an object type.
   if (!(Attributes & (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_copy |
-                      ObjCDeclSpec::DQ_PR_retain)) &&
+                      ObjCDeclSpec::DQ_PR_unsafe_unretained |
+                      ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong |
+                      ObjCDeclSpec::DQ_PR_weak)) &&
       !(Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
       PropertyTy->isObjCObjectPointerType()) {
-    // Skip this warning in gc-only mode.
-    if (getLangOptions().getGCMode() != LangOptions::GCOnly)
-      Diag(Loc, diag::warn_objc_property_no_assignment_attribute);
+    if (getLangOptions().ObjCAutoRefCount)
+      Diag(Loc, diag::err_arc_objc_property_default_assign_on_object);
+    else {
+      // Skip this warning in gc-only mode.
+      if (getLangOptions().getGCMode() != LangOptions::GCOnly)
+        Diag(Loc, diag::warn_objc_property_no_assignment_attribute);
 
-    // If non-gc code warn that this is likely inappropriate.
-    if (getLangOptions().getGCMode() == LangOptions::NonGC)
-      Diag(Loc, diag::warn_objc_property_default_assign_on_object);
+      // If non-gc code warn that this is likely inappropriate.
+      if (getLangOptions().getGCMode() == LangOptions::NonGC)
+        Diag(Loc, diag::warn_objc_property_default_assign_on_object);
+    }
 
     // FIXME: Implement warning dependent on NSCopying being
     // implemented. See also:
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 4bba6f8..2995e2e 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -49,7 +49,8 @@
 static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
                                  bool InOverloadResolution,
                                  StandardConversionSequence &SCS,
-                                 bool CStyle);
+                                 bool CStyle,
+                                 bool AllowObjCWritebackConversion);
   
 static bool IsTransparentUnionStandardConversion(Sema &S, Expr* From, 
                                                  QualType &ToType,
@@ -106,6 +107,7 @@
     ICC_Conversion,
     ICC_Conversion,
     ICC_Conversion,
+    ICC_Conversion,
     ICC_Conversion
   };
   return Category[(int)Kind];
@@ -138,7 +140,8 @@
     ICR_Conversion,
     ICR_Complex_Real_Conversion,
     ICR_Conversion,
-    ICR_Conversion
+    ICR_Conversion,
+    ICR_Writeback_Conversion
   };
   return Rank[(int)Kind];
 }
@@ -170,6 +173,7 @@
     "Complex-real conversion",
     "Block Pointer conversion",
     "Transparent Union Conversion"
+    "Writeback conversion"
   };
   return Name[Kind];
 }
@@ -181,12 +185,14 @@
   Second = ICK_Identity;
   Third = ICK_Identity;
   DeprecatedStringLiteralToCharPtr = false;
+  QualificationIncludesObjCLifetime = false;
   ReferenceBinding = false;
   DirectBinding = false;
   IsLvalueReference = true;
   BindsToFunctionLvalue = false;
   BindsToRvalue = false;
   BindsImplicitObjectArgumentWithoutRefQualifier = false;
+  ObjCLifetimeConversionBinding = false;
   CopyConstructor = 0;
 }
 
@@ -753,15 +759,20 @@
 /// not permitted.
 /// If @p AllowExplicit, then explicit user-defined conversions are
 /// permitted.
+///
+/// \param AllowObjCWritebackConversion Whether we allow the Objective-C
+/// writeback conversion, which allows __autoreleasing id* parameters to
+/// be initialized with __strong id* or __weak id* arguments.
 static ImplicitConversionSequence
 TryImplicitConversion(Sema &S, Expr *From, QualType ToType,
                       bool SuppressUserConversions,
                       bool AllowExplicit,
                       bool InOverloadResolution,
-                      bool CStyle) {
+                      bool CStyle,
+                      bool AllowObjCWritebackConversion) {
   ImplicitConversionSequence ICS;
   if (IsStandardConversion(S, From, ToType, InOverloadResolution,
-                           ICS.Standard, CStyle)) {
+                           ICS.Standard, CStyle, AllowObjCWritebackConversion)){
     ICS.setStandard();
     return ICS;
   }
@@ -867,24 +878,17 @@
   return ICS;
 }
 
-bool Sema::TryImplicitConversion(InitializationSequence &Sequence,
-                                 const InitializedEntity &Entity,
-                                 Expr *Initializer,
-                                 bool SuppressUserConversions,
-                                 bool AllowExplicitConversions,
-                                 bool InOverloadResolution,
-                                 bool CStyle) {
-  ImplicitConversionSequence ICS
-    = clang::TryImplicitConversion(*this, Initializer, Entity.getType(),
-                                   SuppressUserConversions,
-                                   AllowExplicitConversions,
-                                   InOverloadResolution,
-                                   CStyle);
-  if (ICS.isBad()) return true;
-
-  // Perform the actual conversion.
-  Sequence.AddConversionSequenceStep(ICS, Entity.getType());
-  return false;
+ImplicitConversionSequence
+Sema::TryImplicitConversion(Expr *From, QualType ToType,
+                            bool SuppressUserConversions,
+                            bool AllowExplicit,
+                            bool InOverloadResolution,
+                            bool CStyle,
+                            bool AllowObjCWritebackConversion) {
+  return clang::TryImplicitConversion(*this, From, ToType, 
+                                      SuppressUserConversions, AllowExplicit,
+                                      InOverloadResolution, CStyle, 
+                                      AllowObjCWritebackConversion);
 }
 
 /// PerformImplicitConversion - Perform an implicit conversion of the
@@ -903,11 +907,18 @@
 Sema::PerformImplicitConversion(Expr *From, QualType ToType,
                                 AssignmentAction Action, bool AllowExplicit,
                                 ImplicitConversionSequence& ICS) {
+  // Objective-C ARC: Determine whether we will allow the writeback conversion.
+  bool AllowObjCWritebackConversion
+    = getLangOptions().ObjCAutoRefCount && 
+      (Action == AA_Passing || Action == AA_Sending);
+  
+
   ICS = clang::TryImplicitConversion(*this, From, ToType,
                                      /*SuppressUserConversions=*/false,
                                      AllowExplicit,
                                      /*InOverloadResolution=*/false,
-                                     /*CStyle=*/false);
+                                     /*CStyle=*/false,
+                                     AllowObjCWritebackConversion);
   return PerformImplicitConversion(From, ToType, ICS, Action);
 }
 
@@ -1016,7 +1027,8 @@
 static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
                                  bool InOverloadResolution,
                                  StandardConversionSequence &SCS,
-                                 bool CStyle) {
+                                 bool CStyle,
+                                 bool AllowObjCWritebackConversion) {
   QualType FromType = From->getType();
 
   // Standard conversions (C++ [conv])
@@ -1123,6 +1135,7 @@
       // conversion (4.4). (C++ 4.2p2)
       SCS.Second = ICK_Identity;
       SCS.Third = ICK_Qualification;
+      SCS.QualificationIncludesObjCLifetime = false;
       SCS.setAllToTypes(FromType);
       return true;
     }
@@ -1199,7 +1212,10 @@
     SCS.Second = ICK_Floating_Integral;
     FromType = ToType.getUnqualifiedType();
   } else if (S.IsBlockPointerConversion(FromType, ToType, FromType)) {
-               SCS.Second = ICK_Block_Pointer_Conversion;
+    SCS.Second = ICK_Block_Pointer_Conversion;
+  } else if (AllowObjCWritebackConversion &&
+             S.isObjCWritebackConversion(FromType, ToType, FromType)) {
+    SCS.Second = ICK_Writeback_Conversion;
   } else if (S.IsPointerConversion(From, FromType, ToType, InOverloadResolution,
                                    FromType, IncompatibleObjC)) {
     // Pointer conversions (C++ 4.10).
@@ -1235,8 +1251,11 @@
   QualType CanonFrom;
   QualType CanonTo;
   // The third conversion can be a qualification conversion (C++ 4p1).
-  if (S.IsQualificationConversion(FromType, ToType, CStyle)) {
+  bool ObjCLifetimeConversion;
+  if (S.IsQualificationConversion(FromType, ToType, CStyle, 
+                                  ObjCLifetimeConversion)) {
     SCS.Third = ICK_Qualification;
+    SCS.QualificationIncludesObjCLifetime = ObjCLifetimeConversion;
     FromType = ToType;
     CanonFrom = S.Context.getCanonicalType(FromType);
     CanonTo = S.Context.getCanonicalType(ToType);
@@ -1253,7 +1272,8 @@
     if (CanonFrom.getLocalUnqualifiedType()
                                        == CanonTo.getLocalUnqualifiedType() &&
         (CanonFrom.getLocalCVRQualifiers() != CanonTo.getLocalCVRQualifiers()
-         || CanonFrom.getObjCGCAttr() != CanonTo.getObjCGCAttr())) {
+         || CanonFrom.getObjCGCAttr() != CanonTo.getObjCGCAttr()
+         || CanonFrom.getObjCLifetime() != CanonTo.getObjCLifetime())) {
       FromType = ToType;
       CanonFrom = CanonTo;
     }
@@ -1284,7 +1304,8 @@
   for (RecordDecl::field_iterator it = UD->field_begin(),
        itend = UD->field_end();
        it != itend; ++it) {
-    if (IsStandardConversion(S, From, it->getType(), InOverloadResolution, SCS, CStyle)) {
+    if (IsStandardConversion(S, From, it->getType(), InOverloadResolution, SCS,
+                             CStyle, /*ObjCWritebackConversion=*/false)) {
       ToType = it->getType();
       return true;
     }
@@ -1479,16 +1500,18 @@
 /// same type qualifiers as FromPtr has on its pointee type. ToType,
 /// if non-empty, will be a pointer to ToType that may or may not have
 /// the right set of qualifiers on its pointee.
+///
 static QualType
 BuildSimilarlyQualifiedPointerType(const Type *FromPtr,
                                    QualType ToPointee, QualType ToType,
-                                   ASTContext &Context) {
+                                   ASTContext &Context,
+                                   bool StripObjCLifetime = false) {
   assert((FromPtr->getTypeClass() == Type::Pointer ||
           FromPtr->getTypeClass() == Type::ObjCObjectPointer) &&
          "Invalid similarly-qualified pointer type");
 
-  /// \brief Conversions to 'id' subsume cv-qualifier conversions.
-  if (ToType->isObjCIdType() || ToType->isObjCQualifiedIdType())
+  /// Conversions to 'id' subsume cv-qualifier conversions.
+  if (ToType->isObjCIdType() || ToType->isObjCQualifiedIdType()) 
     return ToType.getUnqualifiedType();
 
   QualType CanonFromPointee
@@ -1496,6 +1519,9 @@
   QualType CanonToPointee = Context.getCanonicalType(ToPointee);
   Qualifiers Quals = CanonFromPointee.getQualifiers();
 
+  if (StripObjCLifetime)
+    Quals.removeObjCLifetime();
+  
   // Exact qualifier match -> return the pointer type we're converting to.
   if (CanonToPointee.getLocalQualifiers() == Quals) {
     // ToType is exactly what we need. Return it.
@@ -1599,7 +1625,8 @@
   // Beyond this point, both types need to be pointers
   // , including objective-c pointers.
   QualType ToPointeeType = ToTypePtr->getPointeeType();
-  if (FromType->isObjCObjectPointerType() && ToPointeeType->isVoidType()) {
+  if (FromType->isObjCObjectPointerType() && ToPointeeType->isVoidType() &&
+      !getLangOptions().ObjCAutoRefCount) {
     ConvertedType = BuildSimilarlyQualifiedPointerType(
                                       FromType->getAs<ObjCObjectPointerType>(),
                                                        ToPointeeType,
@@ -1624,7 +1651,8 @@
       ToPointeeType->isVoidType()) {
     ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
                                                        ToPointeeType,
-                                                       ToType, Context);
+                                                       ToType, Context,
+                                                   /*StripObjCLifetime=*/true);
     return true;
   }
 
@@ -1814,6 +1842,7 @@
       ToPointeeType->getAs<ObjCObjectPointerType>() &&
       isObjCPointerConversion(FromPointeeType, ToPointeeType, ConvertedType,
                               IncompatibleObjC)) {
+        
     ConvertedType = Context.getPointerType(ConvertedType);
     ConvertedType = AdoptQualifiers(Context, ConvertedType, FromQualifiers);
     return true;
@@ -1885,6 +1914,73 @@
   return false;
 }
 
+/// \brief Determine whether this is an Objective-C writeback conversion,
+/// used for parameter passing when performing automatic reference counting.
+///
+/// \param FromType The type we're converting form.
+///
+/// \param ToType The type we're converting to.
+///
+/// \param ConvertedType The type that will be produced after applying
+/// this conversion.
+bool Sema::isObjCWritebackConversion(QualType FromType, QualType ToType,
+                                     QualType &ConvertedType) {
+  if (!getLangOptions().ObjCAutoRefCount || 
+      Context.hasSameUnqualifiedType(FromType, ToType))
+    return false;
+  
+  // Parameter must be a pointer to __autoreleasing (with no other qualifiers).
+  QualType ToPointee;
+  if (const PointerType *ToPointer = ToType->getAs<PointerType>())
+    ToPointee = ToPointer->getPointeeType();
+  else
+    return false;
+  
+  Qualifiers ToQuals = ToPointee.getQualifiers();
+  if (!ToPointee->isObjCLifetimeType() || 
+      ToQuals.getObjCLifetime() != Qualifiers::OCL_Autoreleasing ||
+      !ToQuals.withoutObjCGLifetime().empty())
+    return false;
+  
+  // Argument must be a pointer to __strong to __weak.
+  QualType FromPointee;
+  if (const PointerType *FromPointer = FromType->getAs<PointerType>())
+    FromPointee = FromPointer->getPointeeType();
+  else
+    return false;
+  
+  Qualifiers FromQuals = FromPointee.getQualifiers();
+  if (!FromPointee->isObjCLifetimeType() ||
+      (FromQuals.getObjCLifetime() != Qualifiers::OCL_Strong &&
+       FromQuals.getObjCLifetime() != Qualifiers::OCL_Weak))
+    return false;
+  
+  // Make sure that we have compatible qualifiers.
+  FromQuals.setObjCLifetime(Qualifiers::OCL_Autoreleasing);
+  if (!ToQuals.compatiblyIncludes(FromQuals))
+    return false;
+  
+  // Remove qualifiers from the pointee type we're converting from; they
+  // aren't used in the compatibility check belong, and we'll be adding back
+  // qualifiers (with __autoreleasing) if the compatibility check succeeds.
+  FromPointee = FromPointee.getUnqualifiedType();
+  
+  // The unqualified form of the pointee types must be compatible.
+  ToPointee = ToPointee.getUnqualifiedType();
+  bool IncompatibleObjC;
+  if (Context.typesAreCompatible(FromPointee, ToPointee))
+    FromPointee = ToPointee;
+  else if (!isObjCPointerConversion(FromPointee, ToPointee, FromPointee,
+                                    IncompatibleObjC))
+    return false;
+  
+  /// \brief Construct the type we're converting to, which is a pointer to
+  /// __autoreleasing pointee.
+  FromPointee = Context.getQualifiedType(FromPointee, FromQuals);
+  ConvertedType = Context.getPointerType(FromPointee);
+  return true;
+}
+
 bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType,
                                     QualType& ConvertedType) {
   QualType ToPointeeType;
@@ -2178,12 +2274,17 @@
 /// IsQualificationConversion - Determines whether the conversion from
 /// an rvalue of type FromType to ToType is a qualification conversion
 /// (C++ 4.4).
+///
+/// \param ObjCLifetimeConversion Output parameter that will be set to indicate
+/// when the qualification conversion involves a change in the Objective-C
+/// object lifetime.
 bool
 Sema::IsQualificationConversion(QualType FromType, QualType ToType,
-                                bool CStyle) {
+                                bool CStyle, bool &ObjCLifetimeConversion) {
   FromType = Context.getCanonicalType(FromType);
   ToType = Context.getCanonicalType(ToType);
-
+  ObjCLifetimeConversion = false;
+  
   // If FromType and ToType are the same type, this is not a
   // qualification conversion.
   if (FromType.getUnqualifiedType() == ToType.getUnqualifiedType())
@@ -2206,6 +2307,21 @@
     Qualifiers FromQuals = FromType.getQualifiers();
     Qualifiers ToQuals = ToType.getQualifiers();
     
+    // Objective-C ARC:
+    //   Check Objective-C lifetime conversions.
+    if (FromQuals.getObjCLifetime() != ToQuals.getObjCLifetime() &&
+        UnwrappedAnyPointer) {
+      if (ToQuals.compatiblyIncludesObjCLifetime(FromQuals)) {
+        ObjCLifetimeConversion = true;
+        FromQuals.removeObjCLifetime();
+        ToQuals.removeObjCLifetime();
+      } else {
+        // Qualification conversions cannot cast between different
+        // Objective-C lifetime qualifiers.
+        return false;
+      }
+    }
+    
     // Allow addition/removal of GC attributes but not changing GC attributes.
     if (FromQuals.getObjCGCAttr() != ToQuals.getObjCGCAttr() &&
         (!FromQuals.hasObjCGCAttr() || !ToQuals.hasObjCGCAttr())) {
@@ -2713,6 +2829,15 @@
     QualType UnqualT1 = S.Context.getUnqualifiedArrayType(T1, T1Quals);
     QualType UnqualT2 = S.Context.getUnqualifiedArrayType(T2, T2Quals);
     if (UnqualT1 == UnqualT2) {
+      // Objective-C++ ARC: If the references refer to objects with different
+      // lifetimes, prefer bindings that don't change lifetime.
+      if (SCS1.ObjCLifetimeConversionBinding != 
+                                          SCS2.ObjCLifetimeConversionBinding) {
+        return SCS1.ObjCLifetimeConversionBinding
+                                           ? ImplicitConversionSequence::Worse
+                                           : ImplicitConversionSequence::Better;
+      }
+      
       // If the type is an array type, promote the element qualifiers to the
       // type for comparison.
       if (isa<ArrayType>(T1) && T1Quals)
@@ -2722,7 +2847,7 @@
       if (T2.isMoreQualifiedThan(T1))
         return ImplicitConversionSequence::Better;
       else if (T1.isMoreQualifiedThan(T2))
-        return ImplicitConversionSequence::Worse;
+        return ImplicitConversionSequence::Worse;      
     }
   }
 
@@ -2770,6 +2895,17 @@
 
   ImplicitConversionSequence::CompareKind Result
     = ImplicitConversionSequence::Indistinguishable;
+  
+  // Objective-C++ ARC:
+  //   Prefer qualification conversions not involving a change in lifetime
+  //   to qualification conversions that do not change lifetime.
+  if (SCS1.QualificationIncludesObjCLifetime != 
+                                      SCS2.QualificationIncludesObjCLifetime) {
+    Result = SCS1.QualificationIncludesObjCLifetime
+               ? ImplicitConversionSequence::Worse
+               : ImplicitConversionSequence::Better;
+  }
+  
   while (S.Context.UnwrapSimilarPointerTypes(T1, T2)) {
     // Within each iteration of the loop, we check the qualifiers to
     // determine if this still looks like a qualification
@@ -3039,7 +3175,8 @@
 Sema::CompareReferenceRelationship(SourceLocation Loc,
                                    QualType OrigT1, QualType OrigT2,
                                    bool &DerivedToBase,
-                                   bool &ObjCConversion) {
+                                   bool &ObjCConversion,
+                                   bool &ObjCLifetimeConversion) {
   assert(!OrigT1->isReferenceType() &&
     "T1 must be the pointee type of the reference type");
   assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type");
@@ -3056,6 +3193,7 @@
   //   T1 is a base class of T2.
   DerivedToBase = false;
   ObjCConversion = false;
+  ObjCLifetimeConversion = false;
   if (UnqualT1 == UnqualT2) {
     // Nothing to do.
   } else if (!RequireCompleteType(Loc, OrigT2, PDiag()) &&
@@ -3090,9 +3228,16 @@
   // qualifiers when performing these computations, so that e.g., an int in
   // address space 1 is not reference-compatible with an int in address
   // space 2.
+  if (T1Quals.getObjCLifetime() != T2Quals.getObjCLifetime() &&
+      T1Quals.compatiblyIncludesObjCLifetime(T2Quals)) {
+    T1Quals.removeObjCLifetime();
+    T2Quals.removeObjCLifetime();    
+    ObjCLifetimeConversion = true;
+  }
+    
   if (T1Quals == T2Quals)
     return Ref_Compatible;
-  else if (T1.isMoreQualifiedThan(T2))
+  else if (T1Quals.compatiblyIncludes(T2Quals))
     return Ref_Compatible_With_Added_Qualification;
   else
     return Ref_Related;
@@ -3135,13 +3280,14 @@
     if (AllowRvalues) {
       bool DerivedToBase = false;
       bool ObjCConversion = false;
+      bool ObjCLifetimeConversion = false;
       if (!ConvTemplate &&
           S.CompareReferenceRelationship(
             DeclLoc,
             Conv->getConversionType().getNonReferenceType()
               .getUnqualifiedType(),
             DeclType.getNonReferenceType().getUnqualifiedType(),
-            DerivedToBase, ObjCConversion) ==
+            DerivedToBase, ObjCConversion, ObjCLifetimeConversion) ==
           Sema::Ref_Incompatible)
         continue;
     } else {
@@ -3242,10 +3388,11 @@
   bool isRValRef = DeclType->isRValueReferenceType();
   bool DerivedToBase = false;
   bool ObjCConversion = false;
+  bool ObjCLifetimeConversion = false;
   Expr::Classification InitCategory = Init->Classify(S.Context);
   Sema::ReferenceCompareResult RefRelationship
     = S.CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase,
-                                     ObjCConversion);
+                                     ObjCConversion, ObjCLifetimeConversion);
 
 
   // C++0x [dcl.init.ref]p5:
@@ -3283,6 +3430,7 @@
       ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
       ICS.Standard.BindsToRvalue = false;
       ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
+      ICS.Standard.ObjCLifetimeConversionBinding = ObjCLifetimeConversion;
       ICS.Standard.CopyConstructor = 0;
 
       // Nothing more to do: the inaccessibility/ambiguity check for
@@ -3328,7 +3476,7 @@
   //       -- If the initializer expression
   //
   //            -- is an xvalue, class prvalue, array prvalue or function
-  //               lvalue and "cv1T1" is reference-compatible with "cv2 T2", or
+  //               lvalue and "cv1 T1" is reference-compatible with "cv2 T2", or
   if (RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification &&
       (InitCategory.isXValue() ||
       (InitCategory.isPRValue() && (T2->isRecordType() || T2->isArrayType())) ||
@@ -3356,6 +3504,7 @@
     ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
     ICS.Standard.BindsToRvalue = InitCategory.isRValue();
     ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
+    ICS.Standard.ObjCLifetimeConversionBinding = ObjCLifetimeConversion;
     ICS.Standard.CopyConstructor = 0;
     return ICS;
   }
@@ -3398,7 +3547,17 @@
     // we would be reference-compatible or reference-compatible with
     // added qualification. But that wasn't the case, so the reference
     // initialization fails.
-    return ICS;
+    //
+    // Note that we only want to check address spaces and cvr-qualifiers here.
+    // ObjC GC and lifetime qualifiers aren't important.
+    Qualifiers T1Quals = T1.getQualifiers();
+    Qualifiers T2Quals = T2.getQualifiers();
+    T1Quals.removeObjCGCAttr();
+    T1Quals.removeObjCLifetime();
+    T2Quals.removeObjCGCAttr();
+    T2Quals.removeObjCLifetime();
+    if (!T1Quals.compatiblyIncludes(T2Quals))
+      return ICS;
   }
 
   // If at least one of the types is a class type, the types are not
@@ -3429,7 +3588,8 @@
   ICS = TryImplicitConversion(S, Init, T1, SuppressUserConversions,
                               /*AllowExplicit=*/false,
                               /*InOverloadResolution=*/false,
-                              /*CStyle=*/false);
+                              /*CStyle=*/false,
+                              /*AllowObjCWritebackConversion=*/false);
 
   // Of course, that's still a reference binding.
   if (ICS.isStandard()) {
@@ -3438,12 +3598,14 @@
     ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
     ICS.Standard.BindsToRvalue = true;
     ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
+    ICS.Standard.ObjCLifetimeConversionBinding = false;
   } else if (ICS.isUserDefined()) {
     ICS.UserDefined.After.ReferenceBinding = true;
     ICS.Standard.IsLvalueReference = !isRValRef;
     ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
     ICS.Standard.BindsToRvalue = true;
     ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
+    ICS.Standard.ObjCLifetimeConversionBinding = false;
   }
 
   return ICS;
@@ -3458,7 +3620,8 @@
 static ImplicitConversionSequence
 TryCopyInitialization(Sema &S, Expr *From, QualType ToType,
                       bool SuppressUserConversions,
-                      bool InOverloadResolution) {
+                      bool InOverloadResolution,
+                      bool AllowObjCWritebackConversion) {
   if (ToType->isReferenceType())
     return TryReferenceInit(S, From, ToType,
                             /*FIXME:*/From->getLocStart(),
@@ -3469,7 +3632,8 @@
                                SuppressUserConversions,
                                /*AllowExplicit=*/false,
                                InOverloadResolution,
-                               /*CStyle=*/false);
+                               /*CStyle=*/false,
+                               AllowObjCWritebackConversion);
 }
 
 /// TryObjectArgumentInitialization - Try to initialize the object
@@ -3659,7 +3823,8 @@
                                /*SuppressUserConversions=*/false,
                                /*AllowExplicit=*/true,
                                /*InOverloadResolution=*/false,
-                               /*CStyle=*/false);
+                               /*CStyle=*/false,
+                               /*AllowObjCWritebackConversion=*/false);
 }
 
 /// PerformContextuallyConvertToBool - Perform a contextual conversion
@@ -3686,7 +3851,8 @@
                                /*SuppressUserConversions=*/false,
                                /*AllowExplicit=*/true,
                                /*InOverloadResolution=*/false,
-                               /*CStyle=*/false);
+                               /*CStyle=*/false,
+                               /*AllowObjCWritebackConversion=*/false);
 }
 
 /// PerformContextuallyConvertToObjCId - Perform a contextual conversion
@@ -3980,7 +4146,9 @@
       Candidate.Conversions[ArgIdx]
         = TryCopyInitialization(*this, Args[ArgIdx], ParamType,
                                 SuppressUserConversions,
-                                /*InOverloadResolution=*/true);
+                                /*InOverloadResolution=*/true,
+                                /*AllowObjCWritebackConversion=*/
+                                  getLangOptions().ObjCAutoRefCount);
       if (Candidate.Conversions[ArgIdx].isBad()) {
         Candidate.Viable = false;
         Candidate.FailureKind = ovl_fail_bad_conversion;
@@ -4153,7 +4321,9 @@
       Candidate.Conversions[ArgIdx + 1]
         = TryCopyInitialization(*this, Args[ArgIdx], ParamType,
                                 SuppressUserConversions,
-                                /*InOverloadResolution=*/true);
+                                /*InOverloadResolution=*/true,
+                                /*AllowObjCWritebackConversion=*/
+                                  getLangOptions().ObjCAutoRefCount);
       if (Candidate.Conversions[ArgIdx + 1].isBad()) {
         Candidate.Viable = false;
         Candidate.FailureKind = ovl_fail_bad_conversion;
@@ -4374,7 +4544,8 @@
   ImplicitConversionSequence ICS =
     TryCopyInitialization(*this, &Call, ToType,
                           /*SuppressUserConversions=*/true,
-                          /*InOverloadResolution=*/false);
+                          /*InOverloadResolution=*/false,
+                          /*AllowObjCWritebackConversion=*/false);
 
   switch (ICS.getKind()) {
   case ImplicitConversionSequence::StandardConversion:
@@ -4544,7 +4715,9 @@
       Candidate.Conversions[ArgIdx + 1]
         = TryCopyInitialization(*this, Args[ArgIdx], ParamType,
                                 /*SuppressUserConversions=*/false,
-                                /*InOverloadResolution=*/false);
+                                /*InOverloadResolution=*/false,
+                                /*AllowObjCWritebackConversion=*/
+                                  getLangOptions().ObjCAutoRefCount);
       if (Candidate.Conversions[ArgIdx + 1].isBad()) {
         Candidate.Viable = false;
         Candidate.FailureKind = ovl_fail_bad_conversion;
@@ -4662,7 +4835,9 @@
       Candidate.Conversions[ArgIdx]
         = TryCopyInitialization(*this, Args[ArgIdx], ParamTys[ArgIdx],
                                 ArgIdx == 0 && IsAssignmentOperator,
-                                /*InOverloadResolution=*/false);
+                                /*InOverloadResolution=*/false,
+                                /*AllowObjCWritebackConversion=*/
+                                  getLangOptions().ObjCAutoRefCount);
     }
     if (Candidate.Conversions[ArgIdx].isBad()) {
       Candidate.Viable = false;
@@ -6619,6 +6794,17 @@
       return;
     }
 
+    if (FromQs.getObjCLifetime() != ToQs.getObjCLifetime()) {
+      S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_lifetime)
+        << (unsigned) FnKind << FnDesc
+        << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+        << FromTy
+        << FromQs.getObjCLifetime() << ToQs.getObjCLifetime()
+        << (unsigned) isObjectArgument << I+1;
+      MaybeEmitInheritedConstructorNote(S, Fn);
+      return;
+    }
+
     if (FromQs.getObjCGCAttr() != ToQs.getObjCGCAttr()) {
       S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_gc)
       << (unsigned) FnKind << FnDesc
@@ -7152,7 +7338,9 @@
         = TryCopyInitialization(S, Args[ConvIdx],
                                 Cand->BuiltinTypes.ParamTypes[ConvIdx],
                                 SuppressUserConversions,
-                                /*InOverloadResolution*/ true);
+                                /*InOverloadResolution*/ true,
+                                /*AllowObjCWritebackConversion=*/
+                                  S.getLangOptions().ObjCAutoRefCount);
     return;
   }
 
@@ -7163,7 +7351,9 @@
       Cand->Conversions[ConvIdx]
         = TryCopyInitialization(S, Args[ArgIdx], Proto->getArgType(ArgIdx),
                                 SuppressUserConversions,
-                                /*InOverloadResolution=*/true);
+                                /*InOverloadResolution=*/true,
+                                /*AllowObjCWritebackConversion=*/
+                                  S.getLangOptions().ObjCAutoRefCount);
     else
       Cand->Conversions[ConvIdx].setEllipsis();
   }
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index d7c0a54..18e5f7e 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -66,8 +66,29 @@
 
   // If we have an invalid decl, just return.
   if (DG.isNull() || !DG.isSingleDecl()) return;
+  VarDecl *var = cast<VarDecl>(DG.getSingleDecl());
+
   // suppress any potential 'unused variable' warning.
-  DG.getSingleDecl()->setUsed();
+  var->setUsed();
+
+  // In ARC, we don't want to lifetime for the iteration
+  // variable of a fast enumeration loop.  Rather than actually
+  // trying to catch that during declaration processing, we
+  // remove the consequences here.
+  if (getLangOptions().ObjCAutoRefCount) {
+    SplitQualType split = var->getType().split();
+
+    // Inferred lifetime will show up as a local qualifier because
+    // explicit lifetime would have shown up as an AttributedType
+    // instead.
+    if (split.second.hasObjCLifetime()) {
+      // Change the qualification to 'const __unsafe_unretained'.
+      split.second.setObjCLifetime(Qualifiers::OCL_ExplicitNone);
+      split.second.addConst();
+      var->setType(Context.getQualifiedType(split.first, split.second));
+      var->setInit(0);
+    }
+  }
 }
 
 void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
@@ -114,6 +135,10 @@
       }
     }
   } else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
+    if (getLangOptions().ObjCAutoRefCount && ME->isDelegateInitCall()) {
+      Diag(Loc, diag::err_arc_unused_init_message) << R1;
+      return;
+    }
     const ObjCMethodDecl *MD = ME->getMethodDecl();
     if (MD && MD->getAttr<WarnUnusedResultAttr>()) {
       Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result";
@@ -951,14 +976,13 @@
         return StmtError(Diag((*DS->decl_begin())->getLocation(),
                          diag::err_toomany_element_decls));
 
-      Decl *D = DS->getSingleDecl();
-      FirstType = cast<ValueDecl>(D)->getType();
+      VarDecl *D = cast<VarDecl>(DS->getSingleDecl());
+      FirstType = D->getType();
       // C99 6.8.5p3: The declaration part of a 'for' statement shall only
       // declare identifiers for objects having storage class 'auto' or
       // 'register'.
-      VarDecl *VD = cast<VarDecl>(D);
-      if (VD->isLocalVarDecl() && !VD->hasLocalStorage())
-        return StmtError(Diag(VD->getLocation(),
+      if (!D->hasLocalStorage())
+        return StmtError(Diag(D->getLocation(),
                               diag::err_non_variable_decl_in_for));
     } else {
       Expr *FirstE = cast<Expr>(First);
@@ -1047,6 +1071,13 @@
   Decl->setTypeSourceInfo(InitTSI);
   Decl->setType(InitTSI->getType());
 
+  // In ARC, infer lifetime.
+  // FIXME: ARC may want to turn this into 'const __unsafe_unretained' if
+  // we're doing the equivalent of fast iteration.
+  if (SemaRef.getLangOptions().ObjCAutoRefCount && 
+      SemaRef.inferObjCARCLifetime(Decl))
+    Decl->setInvalidDecl();
+
   SemaRef.AddInitializerToDecl(Decl, Init, /*DirectInit=*/false,
                                /*TypeMayContainAuto=*/false);
   SemaRef.FinalizeDeclaration(Decl);
@@ -1797,7 +1828,7 @@
   if (getLangOptions().CPlusPlus && FnRetType->isRecordType() &&
       !CurContext->isDependentContext())
     FunctionScopes.back()->Returns.push_back(Result);
-
+  
   return Owned(Result);
 }
 
@@ -2179,6 +2210,12 @@
                                           HandlerBlock));
 }
 
+StmtResult
+Sema::ActOnObjCAutoreleasePoolStmt(SourceLocation AtLoc, Stmt *Body) {
+  getCurFunction()->setHasBranchProtectedScope();
+  return Owned(new (Context) ObjCAutoreleasePoolStmt(AtLoc, Body));
+}
+
 namespace {
 
 class TypeWithHandler {
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index d458050..b8caad8 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -3503,9 +3503,11 @@
     return true;
   }
 
+  bool ObjCLifetimeConversion;
   if (ParamType->isPointerType() &&
       !ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType() &&
-      S.IsQualificationConversion(ArgType, ParamType, false)) {
+      S.IsQualificationConversion(ArgType, ParamType, false, 
+                                  ObjCLifetimeConversion)) {
     // For pointer-to-object types, qualification conversions are
     // permitted.
   } else {
@@ -3865,8 +3867,9 @@
       return Owned(Arg);
     }
 
+    bool ObjCLifetimeConversion;
     if (IsQualificationConversion(ArgType, ParamType.getNonReferenceType(),
-                                  false)) {
+                                  false, ObjCLifetimeConversion)) {
       Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg)).take();
     } else if (!Context.hasSameUnqualifiedType(ArgType,
                                            ParamType.getNonReferenceType())) {
@@ -3933,9 +3936,11 @@
   //        member, qualification conversions (4.4) are applied.
   assert(ParamType->isMemberPointerType() && "Only pointers to members remain");
 
+  bool ObjCLifetimeConversion;
   if (Context.hasSameUnqualifiedType(ParamType, ArgType)) {
     // Types match exactly: nothing more to do here.
-  } else if (IsQualificationConversion(ArgType, ParamType, false)) {
+  } else if (IsQualificationConversion(ArgType, ParamType, false, 
+                                       ObjCLifetimeConversion)) {
     Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg)).take();
   } else {
     // We can't perform this conversion.
@@ -4043,8 +4048,10 @@
       // We might need to perform a trailing qualification conversion, since
       // the element type on the parameter could be more qualified than the
       // element type in the expression we constructed.
+      bool ObjCLifetimeConversion;
       if (IsQualificationConversion(((Expr*) RefExpr.get())->getType(),
-                                    ParamType.getUnqualifiedType(), false))
+                                    ParamType.getUnqualifiedType(), false,
+                                    ObjCLifetimeConversion))
         RefExpr = ImpCastExprToType(RefExpr.take(), ParamType.getUnqualifiedType(), CK_NoOp);
 
       assert(!RefExpr.isInvalid() &&
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 9011cdf..359c931 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -819,6 +819,11 @@
       ParamQs.hasAddressSpace())
     return true;
 
+  // Mismatched (but not missing) Objective-C lifetime qualifiers.
+  if (ParamQs.getObjCLifetime() != ArgQs.getObjCLifetime() &&
+      ParamQs.hasObjCLifetime())
+    return true;
+  
   // CVR qualifier superset.
   return (ParamQs.getCVRQualifiers() != ArgQs.getCVRQualifiers()) &&
       ((ParamQs.getCVRQualifiers() | ArgQs.getCVRQualifiers())
@@ -1009,6 +1014,8 @@
       DeducedQs.removeObjCGCAttr();
     if (ParamQs.hasAddressSpace())
       DeducedQs.removeAddressSpace();
+    if (ParamQs.hasObjCLifetime())
+      DeducedQs.removeObjCLifetime();
     DeducedType = S.Context.getQualifiedType(DeducedType.getUnqualifiedType(),
                                              DeducedQs);
     
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index ef3c262..bfffb9e 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -26,6 +26,7 @@
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/DelayedDiagnostic.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/Support/ErrorHandling.h"
 using namespace clang;
@@ -110,7 +111,8 @@
 // objc_gc applies to Objective-C pointers or, otherwise, to the
 // smallest available pointer type (i.e. 'void*' in 'void**').
 #define OBJC_POINTER_TYPE_ATTRS_CASELIST \
-    case AttributeList::AT_objc_gc
+    case AttributeList::AT_objc_gc: \
+    case AttributeList::AT_objc_lifetime
 
 // Function type attributes.
 #define FUNCTION_TYPE_ATTRS_CASELIST \
@@ -295,11 +297,15 @@
 static bool handleObjCGCTypeAttr(TypeProcessingState &state,
                                  AttributeList &attr, QualType &type);
 
+static bool handleObjCLifetimeTypeAttr(TypeProcessingState &state,
+                                       AttributeList &attr, QualType &type);
+
 static bool handleObjCPointerTypeAttr(TypeProcessingState &state,
                                       AttributeList &attr, QualType &type) {
-  // Right now, we have exactly one of these attributes: objc_gc.
-  assert(attr.getKind() == AttributeList::AT_objc_gc);
-  return handleObjCGCTypeAttr(state, attr, type);
+  if (attr.getKind() == AttributeList::AT_objc_gc)
+    return handleObjCGCTypeAttr(state, attr, type);
+  assert(attr.getKind() == AttributeList::AT_objc_lifetime);
+  return handleObjCLifetimeTypeAttr(state, attr, type);
 }
 
 /// Given that an objc_gc attribute was written somewhere on a
@@ -447,7 +453,12 @@
     return true;
   }
 
-  return handleFunctionTypeAttr(state, attr, declSpecType);
+  if (handleFunctionTypeAttr(state, attr, declSpecType)) {
+    spliceAttrOutOfList(attr, attrList);
+    return true;
+  }
+
+  return false;
 }
 
 /// A function type attribute was written in the decl spec.  Try to
@@ -512,6 +523,11 @@
       distributeObjCPointerTypeAttrFromDeclarator(state, *attr, declSpecType);
       break;
 
+    case AttributeList::AT_ns_returns_retained:
+      if (!state.getSema().getLangOptions().ObjCAutoRefCount)
+        break;
+      // fallthrough
+
     FUNCTION_TYPE_ATTRS_CASELIST:
       distributeFunctionTypeAttrFromDeclarator(state, *attr, declSpecType);
       break;
@@ -1017,6 +1033,51 @@
   return Context.getParenType(T);
 }
 
+/// Given that we're building a pointer or reference to the given
+static QualType inferARCLifetimeForPointee(Sema &S, QualType type,
+                                           SourceLocation loc,
+                                           bool isReference) {
+  // Bail out if retention is unrequired or already specified.
+  if (!type->isObjCLifetimeType() ||
+      type.getObjCLifetime() != Qualifiers::OCL_None)
+    return type;
+
+  Qualifiers::ObjCLifetime implicitLifetime = Qualifiers::OCL_None;
+
+  // If the object type is const-qualified, we can safely use
+  // __unsafe_unretained.  This is safe (because there are no read
+  // barriers), and it'll be safe to coerce anything but __weak* to
+  // the resulting type.
+  if (type.isConstQualified()) {
+    implicitLifetime = Qualifiers::OCL_ExplicitNone;
+
+  // Otherwise, check whether the static type does not require
+  // retaining.  This currently only triggers for Class (possibly
+  // protocol-qualifed, and arrays thereof).
+  } else if (type->isObjCARCImplicitlyUnretainedType()) {
+    implicitLifetime = Qualifiers::OCL_ExplicitNone;
+
+  // If that failed, give an error and recover using __autoreleasing.
+  } else {
+    // These types can show up in private ivars in system headers, so
+    // we need this to not be an error in those cases.  Instead we
+    // want to delay.
+    if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
+      S.DelayedDiagnostics.add(
+          sema::DelayedDiagnostic::makeForbiddenType(loc,
+              diag::err_arc_indirect_no_lifetime, type, isReference));
+    } else {
+      S.Diag(loc, diag::err_arc_indirect_no_lifetime) << type << isReference;
+    }
+    implicitLifetime = Qualifiers::OCL_Autoreleasing;
+  }
+  assert(implicitLifetime && "didn't infer any lifetime!");
+
+  Qualifiers qs;
+  qs.addObjCLifetime(implicitLifetime);
+  return S.Context.getQualifiedType(type, qs);
+}
+
 /// \brief Build a pointer type.
 ///
 /// \param T The type to which we'll be building a pointer.
@@ -1041,6 +1102,10 @@
 
   assert(!T->isObjCObjectType() && "Should build ObjCObjectPointerType");
 
+  // In ARC, it is forbidden to build pointers to unqualified pointers.
+  if (getLangOptions().ObjCAutoRefCount)
+    T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ false);
+
   // Build the pointer type.
   return Context.getPointerType(T);
 }
@@ -1094,6 +1159,10 @@
     return QualType();
   }
 
+  // In ARC, it is forbidden to build references to unqualified pointers.
+  if (getLangOptions().ObjCAutoRefCount)
+    T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ true);
+
   // Handle restrict on references.
   if (LValueRef)
     return Context.getLValueReferenceType(T, SpelledAsLValue);
@@ -1266,10 +1335,12 @@
   if (!getLangOptions().C99) {
     if (T->isVariableArrayType()) {
       // Prohibit the use of non-POD types in VLAs.
+      QualType BaseT = Context.getBaseElementType(T);
       if (!T->isDependentType() && 
-          !Context.getBaseElementType(T)->isPODType()) {
+          !BaseT.isPODType(Context) &&
+          !BaseT->isObjCLifetimeType()) {
         Diag(Loc, diag::err_vla_non_pod)
-          << Context.getBaseElementType(T);
+          << BaseT;
         return QualType();
       } 
       // Prohibit the use of VLAs during template argument deduction.
@@ -1490,6 +1561,111 @@
   return QT;
 }
 
+/// Given that this is the declaration of a parameter under ARC,
+/// attempt to infer attributes and such for pointer-to-whatever
+/// types.
+static void inferARCWriteback(TypeProcessingState &state,
+                              QualType &declSpecType) {
+  Sema &S = state.getSema();
+  Declarator &declarator = state.getDeclarator();
+
+  // TODO: should we care about decl qualifiers?
+
+  // Check whether the declarator has the expected form.  We walk
+  // from the inside out in order to make the block logic work.
+  unsigned outermostPointerIndex = 0;
+  bool isBlockPointer = false;
+  unsigned numPointers = 0;
+  for (unsigned i = 0, e = declarator.getNumTypeObjects(); i != e; ++i) {
+    unsigned chunkIndex = i;
+    DeclaratorChunk &chunk = declarator.getTypeObject(chunkIndex);
+    switch (chunk.Kind) {
+    case DeclaratorChunk::Paren:
+      // Ignore parens.
+      break;
+
+    case DeclaratorChunk::Reference:
+    case DeclaratorChunk::Pointer:
+      // Count the number of pointers.  Treat references
+      // interchangeably as pointers; if they're mis-ordered, normal
+      // type building will discover that.
+      outermostPointerIndex = chunkIndex;
+      numPointers++;
+      break;
+
+    case DeclaratorChunk::BlockPointer:
+      // If we have a pointer to block pointer, that's an acceptable
+      // indirect reference; anything else is not an application of
+      // the rules.
+      if (numPointers != 1) return;
+      numPointers++;
+      outermostPointerIndex = chunkIndex;
+      isBlockPointer = true;
+
+      // We don't care about pointer structure in return values here.
+      goto done;
+
+    case DeclaratorChunk::Array: // suppress if written (id[])?
+    case DeclaratorChunk::Function:
+    case DeclaratorChunk::MemberPointer:
+      return;
+    }
+  }
+ done:
+
+  // If we have *one* pointer, then we want to throw the qualifier on
+  // the declaration-specifiers, which means that it needs to be a
+  // retainable object type.
+  if (numPointers == 1) {
+    // If it's not a retainable object type, the rule doesn't apply.
+    if (!declSpecType->isObjCRetainableType()) return;
+
+    // If it already has lifetime, don't do anything.
+    if (declSpecType.getObjCLifetime()) return;
+
+    // Otherwise, modify the type in-place.
+    Qualifiers qs;
+    
+    if (declSpecType->isObjCARCImplicitlyUnretainedType())
+      qs.addObjCLifetime(Qualifiers::OCL_ExplicitNone);
+    else
+      qs.addObjCLifetime(Qualifiers::OCL_Autoreleasing);
+    declSpecType = S.Context.getQualifiedType(declSpecType, qs);
+
+  // If we have *two* pointers, then we want to throw the qualifier on
+  // the outermost pointer.
+  } else if (numPointers == 2) {
+    // If we don't have a block pointer, we need to check whether the
+    // declaration-specifiers gave us something that will turn into a
+    // retainable object pointer after we slap the first pointer on it.
+    if (!isBlockPointer && !declSpecType->isObjCObjectType())
+      return;
+
+    // Look for an explicit lifetime attribute there.
+    DeclaratorChunk &chunk = declarator.getTypeObject(outermostPointerIndex);
+    assert(chunk.Kind == DeclaratorChunk::Pointer ||
+           chunk.Kind == DeclaratorChunk::BlockPointer);
+    for (const AttributeList *attr = chunk.getAttrs(); attr;
+           attr = attr->getNext())
+      if (attr->getKind() == AttributeList::AT_objc_lifetime)
+        return;
+
+    // If there wasn't one, add one (with an invalid source location
+    // so that we don't make an AttributedType for it).
+    AttributeList *attr = declarator.getAttributePool()
+      .create(&S.Context.Idents.get("objc_lifetime"), SourceLocation(),
+              /*scope*/ 0, SourceLocation(),
+              &S.Context.Idents.get("autoreleasing"), SourceLocation(),
+              /*args*/ 0, 0,
+              /*declspec*/ false, /*C++0x*/ false);
+    spliceAttrIntoList(*attr, chunk.getAttrListRef());
+
+  // Any other number of pointers/references does not trigger the rule.
+  } else return;
+
+  // TODO: mark whether we did this inference?
+}
+
 static void DiagnoseIgnoredQualifiers(unsigned Quals,
                                       SourceLocation ConstQualLoc,
                                       SourceLocation VolatileQualLoc,
@@ -1599,6 +1775,9 @@
   if (D.getAttributes())
     distributeTypeAttrsFromDeclarator(state, T);
 
+  if (D.isPrototypeContext() && getLangOptions().ObjCAutoRefCount)
+    inferARCWriteback(state, T);
+
   // C++0x [dcl.spec.auto]p5: reject 'auto' if it is not in an allowed context.
   // In C++0x, a function declarator using 'auto' must have a trailing return
   // type (this is checked later) and we can skip this. In other languages
@@ -1922,6 +2101,10 @@
         llvm::SmallVector<QualType, 16> ArgTys;
         ArgTys.reserve(FTI.NumArgs);
 
+        llvm::SmallVector<bool, 16> ConsumedArguments;
+        ConsumedArguments.reserve(FTI.NumArgs);
+        bool HasAnyConsumedArguments = false;
+
         for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
           ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[i].Param);
           QualType ArgTy = Param->getType();
@@ -1967,9 +2150,18 @@
             }
           }
 
+          if (getLangOptions().ObjCAutoRefCount) {
+            bool Consumed = Param->hasAttr<NSConsumedAttr>();
+            ConsumedArguments.push_back(Consumed);
+            HasAnyConsumedArguments |= Consumed;
+          }
+
           ArgTys.push_back(ArgTy);
         }
 
+        if (HasAnyConsumedArguments)
+          EPI.ConsumedArguments = ConsumedArguments.data();
+
         llvm::SmallVector<QualType, 4> Exceptions;
         EPI.ExceptionSpecType = FTI.getExceptionSpecType();
         if (FTI.getExceptionSpecType() == EST_Dynamic) {
@@ -2282,6 +2474,8 @@
     return AttributeList::AT_neon_polyvector_type;
   case AttributedType::attr_objc_gc:
     return AttributeList::AT_objc_gc;
+  case AttributedType::attr_objc_lifetime:
+    return AttributeList::AT_objc_lifetime;
   case AttributedType::attr_noreturn:
     return AttributeList::AT_noreturn;
   case AttributedType::attr_cdecl:
@@ -2512,6 +2706,9 @@
       llvm_unreachable("qualified type locs not expected here!");
     }
 
+    void VisitAttributedTypeLoc(AttributedTypeLoc TL) {
+      fillAttributedTypeLoc(TL, Chunk.getAttrs());
+    }
     void VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
       assert(Chunk.Kind == DeclaratorChunk::BlockPointer);
       TL.setCaretLoc(Chunk.Loc);
@@ -2707,8 +2904,6 @@
   return CreateParsedType(T, TInfo);
 }
 
-
-
 //===----------------------------------------------------------------------===//
 // Type Attribute Processing
 //===----------------------------------------------------------------------===//
@@ -2767,6 +2962,83 @@
   Type = S.Context.getAddrSpaceQualType(Type, ASIdx);
 }
 
+/// handleObjCLifetimeTypeAttr - Process an objc_lifetime
+/// attribute on the specified type.
+///
+/// Returns 'true' if the attribute was handled.
+static bool handleObjCLifetimeTypeAttr(TypeProcessingState &state,
+                                       AttributeList &attr,
+                                       QualType &type) {
+  if (!type->isObjCRetainableType() && !type->isDependentType())
+    return false;
+
+  Sema &S = state.getSema();
+
+  if (type.getQualifiers().getObjCLifetime()) {
+    S.Diag(attr.getLoc(), diag::err_attr_objc_lifetime_redundant)
+      << type;
+    return true;
+  }
+
+  if (!attr.getParameterName()) {
+    S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string)
+      << "objc_lifetime" << 1;
+    attr.setInvalid();
+    return true;
+  }
+
+  Qualifiers::ObjCLifetime lifetime;
+  if (attr.getParameterName()->isStr("none"))
+    lifetime = Qualifiers::OCL_ExplicitNone;
+  else if (attr.getParameterName()->isStr("strong"))
+    lifetime = Qualifiers::OCL_Strong;
+  else if (attr.getParameterName()->isStr("weak"))
+    lifetime = Qualifiers::OCL_Weak;
+  else if (attr.getParameterName()->isStr("autoreleasing"))
+    lifetime = Qualifiers::OCL_Autoreleasing;
+  else {
+    S.Diag(attr.getLoc(), diag::warn_attribute_type_not_supported)
+      << "objc_lifetime" << attr.getParameterName();
+    attr.setInvalid();
+    return true;
+  }
+
+  // Consume lifetime attributes without further comment outside of
+  // ARC mode.
+  if (!S.getLangOptions().ObjCAutoRefCount)
+    return true;
+
+  Qualifiers qs;
+  qs.setObjCLifetime(lifetime);
+  QualType origType = type;
+  type = S.Context.getQualifiedType(type, qs);
+
+  // If we have a valid source location for the attribute, use an
+  // AttributedType instead.
+  if (attr.getLoc().isValid())
+    type = S.Context.getAttributedType(AttributedType::attr_objc_lifetime,
+                                       origType, type);
+
+  // Forbid __weak if we don't have a runtime.
+  if (lifetime == Qualifiers::OCL_Weak &&
+      S.getLangOptions().ObjCNoAutoRefCountRuntime) {
+
+    // Actually, delay this until we know what we're parsing.
+    if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
+      S.DelayedDiagnostics.add(
+          sema::DelayedDiagnostic::makeForbiddenType(attr.getLoc(),
+              diag::err_arc_weak_no_runtime, type, /*ignored*/ 0));
+    } else {
+      S.Diag(attr.getLoc(), diag::err_arc_weak_no_runtime);
+    }
+
+    attr.setInvalid();
+    return true;
+  }
+
+  return true;
+}
+
 /// handleObjCGCTypeAttr - Process the __attribute__((objc_gc)) type
 /// attribute on the specified type.  Returns true to indicate that
 /// the attribute was handled, false to indicate that the type does
@@ -2977,6 +3249,23 @@
     return true;
   }
 
+  // ns_returns_retained is not always a type attribute, but if we got
+  // here, we're treating it as one right now.
+  if (attr.getKind() == AttributeList::AT_ns_returns_retained) {
+    assert(S.getLangOptions().ObjCAutoRefCount &&
+           "ns_returns_retained treated as type attribute in non-ARC");
+    if (attr.getNumArgs()) return true;
+
+    // Delay if this is not a function type.
+    if (!unwrapped.isFunctionType())
+      return false;
+
+    FunctionType::ExtInfo EI
+      = unwrapped.get()->getExtInfo().withProducesResult(true);
+    type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
+    return true;
+  }
+
   if (attr.getKind() == AttributeList::AT_regparm) {
     unsigned value;
     if (S.CheckRegparmAttr(attr, value))
@@ -3288,11 +3577,15 @@
                                VectorType::NeonPolyVector,
                                "neon_polyvector_type");
       break;
-
     case AttributeList::AT_opencl_image_access:
       HandleOpenCLImageAccessAttribute(type, attr, state.getSema());
       break;
 
+    case AttributeList::AT_ns_returns_retained:
+      if (!state.getSema().getLangOptions().ObjCAutoRefCount)
+	break;
+      // fallthrough into the function attrs
+
     FUNCTION_TYPE_ATTRS_CASELIST:
       // Never process function type attributes as part of the
       // declaration-specifiers.
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index ff2e46a..ba4ee34 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1192,6 +1192,16 @@
                                                  Body);
   }
 
+  /// \brief Build a new Objective-C @autoreleasepool statement.
+  ///
+  /// By default, performs semantic analysis to build the new statement.
+  /// Subclasses may override this routine to provide different behavior.
+  StmtResult RebuildObjCAutoreleasePoolStmt(SourceLocation AtLoc,
+                                            Stmt *Body) {
+    return getSema().ActOnObjCAutoreleasePoolStmt(AtLoc, Body);
+  }
+  
+
   /// \brief Build a new Objective-C fast enumeration statement.
   ///
   /// By default, performs semantic analysis to build the new statement.
@@ -3162,6 +3172,13 @@
   if (Result->isFunctionType() || Result->isReferenceType())
     return Result;
 
+  // Suppress Objective-C lifetime qualifiers if they don't make sense for the
+  // resulting type or if the resulting type already has one.
+  if (Quals.hasObjCLifetime() && 
+      (Result.getObjCLifetime() ||
+       (!Result->isObjCLifetimeType() && !Result->isDependentType())))
+    Quals.removeObjCLifetime();
+  
   if (!Quals.empty()) {
     Result = SemaRef.BuildQualifiedType(Result, T.getBeginLoc(), Quals);
     TLB.push<QualifiedTypeLoc>(Result);
@@ -3333,7 +3350,11 @@
     if (Result.isNull())
       return QualType();
   }
-                                                            
+               
+  // Objective-C ARC can add lifetime qualifiers to the type that we're
+  // pointing to.
+  TLB.TypeWasModifiedSafely(Result->getPointeeType());
+  
   PointerTypeLoc NewT = TLB.push<PointerTypeLoc>(Result);
   NewT.setSigilLoc(TL.getSigilLoc());
   return Result;  
@@ -3387,6 +3408,11 @@
       return QualType();
   }
 
+  // Objective-C ARC can add lifetime qualifiers to the type that we're
+  // referring to.
+  TLB.TypeWasModifiedSafely(
+                     Result->getAs<ReferenceType>()->getPointeeTypeAsWritten());
+
   // r-value references can be rebuilt as l-value references.
   ReferenceTypeLoc NewTL;
   if (isa<LValueReferenceType>(Result))
@@ -5435,6 +5461,25 @@
 
 template<typename Derived>
 StmtResult
+TreeTransform<Derived>::TransformObjCAutoreleasePoolStmt(
+                                              ObjCAutoreleasePoolStmt *S) {
+  // Transform the body.
+  StmtResult Body = getDerived().TransformStmt(S->getSubStmt());
+  if (Body.isInvalid())
+    return StmtError();
+  
+  // If nothing changed, just retain this statement.
+  if (!getDerived().AlwaysRebuild() &&
+      Body.get() == S->getSubStmt())
+    return SemaRef.Owned(S);
+
+  // Build a new statement.
+  return getDerived().RebuildObjCAutoreleasePoolStmt(
+                        S->getAtLoc(), Body.get());
+}
+
+template<typename Derived>
+StmtResult
 TreeTransform<Derived>::TransformObjCForCollectionStmt(
                                                   ObjCForCollectionStmt *S) {
   // Transform the element statement.
@@ -7609,6 +7654,43 @@
 }
 
 template<typename Derived>
+ExprResult TreeTransform<Derived>::
+TransformObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) {
+  ExprResult result = getDerived().TransformExpr(E->getSubExpr());
+  if (result.isInvalid()) return ExprError();
+  Expr *subExpr = result.take();
+
+  if (!getDerived().AlwaysRebuild() &&
+      subExpr == E->getSubExpr())
+    return SemaRef.Owned(E);
+
+  return SemaRef.Owned(new(SemaRef.Context)
+      ObjCIndirectCopyRestoreExpr(subExpr, E->getType(), E->shouldCopy()));
+}
+
+template<typename Derived>
+ExprResult TreeTransform<Derived>::
+TransformObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
+  TypeSourceInfo *TSInfo 
+    = getDerived().TransformType(E->getTypeInfoAsWritten());
+  if (!TSInfo)
+    return ExprError();
+  
+  ExprResult Result = getDerived().TransformExpr(E->getSubExpr());
+  if (Result.isInvalid()) 
+    return ExprError();
+  
+  if (!getDerived().AlwaysRebuild() &&
+      TSInfo == E->getTypeInfoAsWritten() &&
+      Result.get() == E->getSubExpr())
+    return SemaRef.Owned(E);
+  
+  return SemaRef.BuildObjCBridgedCast(E->getLParenLoc(), E->getBridgeKind(),
+                                      E->getBridgeKeywordLoc(), TSInfo, 
+                                      Result.get());
+}
+
+template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) {
   // Transform arguments.
diff --git a/lib/Sema/TypeLocBuilder.h b/lib/Sema/TypeLocBuilder.h
index 3570737..f0944f1 100644
--- a/lib/Sema/TypeLocBuilder.h
+++ b/lib/Sema/TypeLocBuilder.h
@@ -87,6 +87,15 @@
     Index = Capacity;
   }  
 
+  /// \brief Tell the TypeLocBuilder that the type it is storing has been
+  /// modified in some safe way that doesn't affect type-location information.
+  void TypeWasModifiedSafely(QualType T) {
+#ifndef NDEBUG
+    assert(T.getLocalUnqualifiedType() == LastTy.getLocalUnqualifiedType());
+    LastTy = T;
+#endif
+  }
+  
   /// Pushes space for a new TypeLoc of the given type.  Invalidates
   /// any TypeLocs previously retrieved from this builder.
   template <class TyLocType> TyLocType push(QualType T) {