[cfe-commits] r133103 - in /cfe/trunk: docs/ include/clang/AST/ include/clang/Basic/ include/clang/Driver/ include/clang/Frontend/ include/clang/Parse/ include/clang/Rewrite/ include/clang/Sema/ include/clang/Serialization/ lib/AST/ lib/Analysis/ lib/Basic/ lib/CodeGen/ lib/Driver/ lib/Frontend/ lib/Lex/ lib/Parse/ lib/Rewrite/ lib/Sema/ lib/Serialization/ lib/StaticAnalyzer/Checkers/ lib/StaticAnalyzer/Core/ test/Analysis/ test/CodeGenObjC/ test/CodeGenObjCXX/ test/Driver/ test/Index/ test/Lexer/ test/PCH/ test/PCH/I...

John McCall rjmccall at apple.com
Wed Jun 15 16:02:43 PDT 2011


Author: rjmccall
Date: Wed Jun 15 18:02:42 2011
New Revision: 133103

URL: http://llvm.org/viewvc/llvm-project?rev=133103&view=rev
Log:
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.


Added:
    cfe/trunk/test/Analysis/objc-arc.m
    cfe/trunk/test/CodeGenObjC/arc-arm.m
    cfe/trunk/test/CodeGenObjC/arc-block-ivar-layout.m
    cfe/trunk/test/CodeGenObjC/arc-bridged-cast.m
    cfe/trunk/test/CodeGenObjC/arc-foreach.m
    cfe/trunk/test/CodeGenObjC/arc-ivar-layout.m
    cfe/trunk/test/CodeGenObjC/arc-no-runtime.m
    cfe/trunk/test/CodeGenObjC/arc-related-result-type.m
    cfe/trunk/test/CodeGenObjC/arc-unopt.m
    cfe/trunk/test/CodeGenObjC/arc-weak-property.m
    cfe/trunk/test/CodeGenObjC/arc.m
    cfe/trunk/test/CodeGenObjC/autorelease.m
    cfe/trunk/test/CodeGenObjC/mrr-autorelease.m
    cfe/trunk/test/CodeGenObjC/nonlazy-msgSend.m
    cfe/trunk/test/CodeGenObjC/related-result-type.m
    cfe/trunk/test/CodeGenObjCXX/arc-globals.mm
    cfe/trunk/test/CodeGenObjCXX/arc-mangle.mm
    cfe/trunk/test/CodeGenObjCXX/arc-new-delete.mm
    cfe/trunk/test/CodeGenObjCXX/arc-pseudo-destructors.mm
    cfe/trunk/test/CodeGenObjCXX/arc-references.mm
    cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm
    cfe/trunk/test/CodeGenObjCXX/arc.mm
    cfe/trunk/test/CodeGenObjCXX/copy.mm
    cfe/trunk/test/Driver/arc-exceptions.m
    cfe/trunk/test/Driver/arc.c
    cfe/trunk/test/Driver/ios-simulator-arcruntime.c
    cfe/trunk/test/Driver/no-objc-arr.m
    cfe/trunk/test/Index/arc-annotate.m
    cfe/trunk/test/Index/arc-complete.m
    cfe/trunk/test/Lexer/has_feature_objc_arc.m
    cfe/trunk/test/PCH/Inputs/arc.h
    cfe/trunk/test/PCH/arc.m
    cfe/trunk/test/SemaObjC/Inputs/
    cfe/trunk/test/SemaObjC/Inputs/arc-system-header.h
    cfe/trunk/test/SemaObjC/arc-bridged-cast.m
    cfe/trunk/test/SemaObjC/arc-decls.m
    cfe/trunk/test/SemaObjC/arc-no-runtime.m
    cfe/trunk/test/SemaObjC/arc-non-pod-memaccess.m
    cfe/trunk/test/SemaObjC/arc-property-decl-attrs.m
    cfe/trunk/test/SemaObjC/arc-property-lifetime.m
    cfe/trunk/test/SemaObjC/arc-property.m
    cfe/trunk/test/SemaObjC/arc-system-header.m
    cfe/trunk/test/SemaObjC/arc-type-conversion.m
    cfe/trunk/test/SemaObjC/arc-unsafe_unretained.m
    cfe/trunk/test/SemaObjC/arc.m
    cfe/trunk/test/SemaObjC/autoreleasepool.m
    cfe/trunk/test/SemaObjC/warn-retain-cycle.m
    cfe/trunk/test/SemaObjC/weak-property.m
    cfe/trunk/test/SemaObjCXX/Inputs/
    cfe/trunk/test/SemaObjCXX/Inputs/arc-system-header.h
    cfe/trunk/test/SemaObjCXX/arc-0x.mm
    cfe/trunk/test/SemaObjCXX/arc-bool-conversion.mm
    cfe/trunk/test/SemaObjCXX/arc-bridged-cast.mm
    cfe/trunk/test/SemaObjCXX/arc-libcxx.mm
    cfe/trunk/test/SemaObjCXX/arc-libstdcxx.mm
    cfe/trunk/test/SemaObjCXX/arc-memfunc.mm
    cfe/trunk/test/SemaObjCXX/arc-non-pod.mm
    cfe/trunk/test/SemaObjCXX/arc-object-init-destroy.mm
    cfe/trunk/test/SemaObjCXX/arc-overloading.mm
    cfe/trunk/test/SemaObjCXX/arc-system-header.mm
    cfe/trunk/test/SemaObjCXX/arc-templates.mm
    cfe/trunk/test/SemaObjCXX/arc-type-conversion.mm
    cfe/trunk/test/SemaObjCXX/arc-type-traits.mm
Modified:
    cfe/trunk/docs/LanguageExtensions.html
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/include/clang/AST/CanonicalType.h
    cfe/trunk/include/clang/AST/DeclObjC.h
    cfe/trunk/include/clang/AST/Expr.h
    cfe/trunk/include/clang/AST/ExprObjC.h
    cfe/trunk/include/clang/AST/OperationKinds.h
    cfe/trunk/include/clang/AST/ParentMap.h
    cfe/trunk/include/clang/AST/PrettyPrinter.h
    cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
    cfe/trunk/include/clang/AST/Stmt.h
    cfe/trunk/include/clang/AST/StmtObjC.h
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticGroups.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Basic/LangOptions.h
    cfe/trunk/include/clang/Basic/StmtNodes.td
    cfe/trunk/include/clang/Basic/TokenKinds.def
    cfe/trunk/include/clang/Driver/CC1Options.td
    cfe/trunk/include/clang/Driver/Options.td
    cfe/trunk/include/clang/Driver/ToolChain.h
    cfe/trunk/include/clang/Frontend/CodeGenOptions.h
    cfe/trunk/include/clang/Frontend/FrontendOptions.h
    cfe/trunk/include/clang/Frontend/PreprocessorOptions.h
    cfe/trunk/include/clang/Frontend/Utils.h
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/include/clang/Rewrite/Rewriter.h
    cfe/trunk/include/clang/Sema/AttributeList.h
    cfe/trunk/include/clang/Sema/DeclSpec.h
    cfe/trunk/include/clang/Sema/DelayedDiagnostic.h
    cfe/trunk/include/clang/Sema/Initialization.h
    cfe/trunk/include/clang/Sema/Overload.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/include/clang/Serialization/ASTBitCodes.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/AST/DeclObjC.cpp
    cfe/trunk/lib/AST/DeclPrinter.cpp
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/AST/ExprClassification.cpp
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/AST/ItaniumMangle.cpp
    cfe/trunk/lib/AST/ParentMap.cpp
    cfe/trunk/lib/AST/StmtPrinter.cpp
    cfe/trunk/lib/AST/StmtProfile.cpp
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/lib/AST/TypePrinter.cpp
    cfe/trunk/lib/Analysis/ReachableCode.cpp
    cfe/trunk/lib/Basic/DiagnosticIDs.cpp
    cfe/trunk/lib/Basic/IdentifierTable.cpp
    cfe/trunk/lib/Basic/Targets.cpp
    cfe/trunk/lib/CodeGen/CGBlocks.cpp
    cfe/trunk/lib/CodeGen/CGBlocks.h
    cfe/trunk/lib/CodeGen/CGCall.cpp
    cfe/trunk/lib/CodeGen/CGCall.h
    cfe/trunk/lib/CodeGen/CGClass.cpp
    cfe/trunk/lib/CodeGen/CGDebugInfo.cpp
    cfe/trunk/lib/CodeGen/CGDecl.cpp
    cfe/trunk/lib/CodeGen/CGDeclCXX.cpp
    cfe/trunk/lib/CodeGen/CGException.cpp
    cfe/trunk/lib/CodeGen/CGExpr.cpp
    cfe/trunk/lib/CodeGen/CGExprAgg.cpp
    cfe/trunk/lib/CodeGen/CGExprCXX.cpp
    cfe/trunk/lib/CodeGen/CGExprConstant.cpp
    cfe/trunk/lib/CodeGen/CGExprScalar.cpp
    cfe/trunk/lib/CodeGen/CGObjC.cpp
    cfe/trunk/lib/CodeGen/CGObjCGNU.cpp
    cfe/trunk/lib/CodeGen/CGObjCMac.cpp
    cfe/trunk/lib/CodeGen/CGObjCRuntime.h
    cfe/trunk/lib/CodeGen/CGStmt.cpp
    cfe/trunk/lib/CodeGen/CGValue.h
    cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/lib/CodeGen/CodeGenModule.cpp
    cfe/trunk/lib/CodeGen/CodeGenModule.h
    cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
    cfe/trunk/lib/CodeGen/TargetInfo.cpp
    cfe/trunk/lib/CodeGen/TargetInfo.h
    cfe/trunk/lib/Driver/ToolChain.cpp
    cfe/trunk/lib/Driver/ToolChains.cpp
    cfe/trunk/lib/Driver/ToolChains.h
    cfe/trunk/lib/Driver/Tools.cpp
    cfe/trunk/lib/Frontend/CompilerInvocation.cpp
    cfe/trunk/lib/Frontend/InitPreprocessor.cpp
    cfe/trunk/lib/Lex/PPMacroExpansion.cpp
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseExpr.cpp
    cfe/trunk/lib/Parse/ParseObjc.cpp
    cfe/trunk/lib/Rewrite/FixItRewriter.cpp
    cfe/trunk/lib/Rewrite/Rewriter.cpp
    cfe/trunk/lib/Sema/AttributeList.cpp
    cfe/trunk/lib/Sema/DelayedDiagnostic.cpp
    cfe/trunk/lib/Sema/JumpDiagnostics.cpp
    cfe/trunk/lib/Sema/Sema.cpp
    cfe/trunk/lib/Sema/SemaCXXCast.cpp
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/lib/Sema/SemaCodeComplete.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclAttr.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaDeclObjC.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaExprObjC.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/lib/Sema/SemaObjCProperty.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaStmt.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/lib/Sema/TypeLocBuilder.h
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
    cfe/trunk/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
    cfe/trunk/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
    cfe/trunk/test/Analysis/pr4209.m
    cfe/trunk/test/CodeGenObjC/block-6.m
    cfe/trunk/test/Index/complete-exprs.m
    cfe/trunk/test/Index/complete-property-flags.m
    cfe/trunk/test/SemaObjC/class-unavail-warning.m
    cfe/trunk/test/SemaObjC/error-property-gc-attr.m
    cfe/trunk/test/SemaObjC/property-10.m
    cfe/trunk/test/SemaObjC/special-dep-unavail-warning.m
    cfe/trunk/test/SemaObjC/synthesized-ivar.m
    cfe/trunk/tools/libclang/CIndex.cpp
    cfe/trunk/tools/libclang/CXCursor.cpp
    cfe/trunk/tools/libclang/CXType.cpp

Modified: cfe/trunk/docs/LanguageExtensions.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LanguageExtensions.html?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/docs/LanguageExtensions.html (original)
+++ cfe/trunk/docs/LanguageExtensions.html Wed Jun 15 18:02:42 2011
@@ -65,6 +65,7 @@
 <li><a href="#objc_features">Objective-C Features</a>
   <ul>
     <li><a href="#objc_instancetype">Related result types</a></li>
+    <li><a href="#objc_arc">Automatic reference counting</a></li>
   </ul>
 </li>
 <li><a href="#overloading-in-c">Function Overloading in C</a></li>
@@ -670,6 +671,12 @@
 related result type.</p>
 
 <!-- ======================================================================= -->
+<h2 id="objc_arc">Automatic reference counting </h2>
+<!-- ======================================================================= -->
+
+<p>Clang provides support for <a href="AutomaticReferenceCounting.html">automated reference counting</a> in Objective-C, which eliminates the need for manual retain/release/autorelease message sends. There are two feature macros associated with automatic reference counting: <code>__has_feature(objc_arc)</code> indicates the availability of automated reference counting in general, while <code>__has_feature(objc_arc_weak)</code> indicates that automated reference counting also includes support for <code>__weak</code> pointers to Objective-C objects.</p>
+
+<!-- ======================================================================= -->
 <h2 id="overloading-in-c">Function Overloading in C</h2>
 <!-- ======================================================================= -->
 

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Wed Jun 15 18:02:42 2011
@@ -993,6 +993,18 @@
     return getExtQualType(T, Qs);
   }
 
+  /// getLifetimeQualifiedType - Returns a type with the given
+  /// lifetime qualifier.
+  QualType getLifetimeQualifiedType(QualType type,
+                                    Qualifiers::ObjCLifetime lifetime) {
+    assert(type.getObjCLifetime() == Qualifiers::OCL_None);
+    assert(lifetime != Qualifiers::OCL_None);
+
+    Qualifiers qs;
+    qs.addObjCLifetime(lifetime);
+    return getQualifiedType(type, qs);
+  }
+
   DeclarationNameInfo getNameForTemplate(TemplateName Name,
                                          SourceLocation NameLoc) const;
 
@@ -1044,7 +1056,9 @@
 
   /// isObjCNSObjectType - Return true if this is an NSObject object with
   /// its NSObject attribute set.
-  bool isObjCNSObjectType(QualType Ty) const;
+  static bool isObjCNSObjectType(QualType Ty) {
+    return Ty->isObjCNSObjectType();
+  }
 
   //===--------------------------------------------------------------------===//
   //                         Type Sizing and Analysis

Modified: cfe/trunk/include/clang/AST/CanonicalType.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/CanonicalType.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/CanonicalType.h (original)
+++ cfe/trunk/include/clang/AST/CanonicalType.h Wed Jun 15 18:02:42 2011
@@ -250,7 +250,6 @@
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjectType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteOrObjectType)
-  LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isPODType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVariablyModifiedType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIntegerType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isEnumeralType)
@@ -295,6 +294,7 @@
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnsignedIntegerOrEnumerationType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isConstantSizeType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSpecifierType)
+  LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(CXXRecordDecl*, getAsCXXRecordDecl)
 
   /// \brief Retrieve the proxy-adaptor type.
   ///

Modified: cfe/trunk/include/clang/AST/DeclObjC.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclObjC.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclObjC.h (original)
+++ cfe/trunk/include/clang/AST/DeclObjC.h Wed Jun 15 18:02:42 2011
@@ -1240,6 +1240,9 @@
   /// IvarInitializers - The arguments used to initialize the ivars
   CXXCtorInitializer **IvarInitializers;
   unsigned NumIvarInitializers;
+
+  /// true if class has a .cxx_[construct,destruct] method.
+  bool HasCXXStructors : 1;
   
   /// true of class extension has at least one bitfield ivar.
   bool HasSynthBitfield : 1;
@@ -1249,7 +1252,7 @@
                          ObjCInterfaceDecl *superDecl)
     : ObjCImplDecl(ObjCImplementation, DC, L, classInterface),
        SuperClass(superDecl), IvarInitializers(0), NumIvarInitializers(0),
-       HasSynthBitfield(false) {}
+       HasCXXStructors(false), HasSynthBitfield(false) {}
 public:
   static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC,
                                         SourceLocation L,
@@ -1287,6 +1290,9 @@
   void setIvarInitializers(ASTContext &C,
                            CXXCtorInitializer ** initializers,
                            unsigned numInitializers);
+
+  bool hasCXXStructors() const { return HasCXXStructors; }
+  void setHasCXXStructors(bool val) { HasCXXStructors = val; }
   
   bool hasSynthBitfield() const { return HasSynthBitfield; }
   void setHasSynthBitfield (bool val) { HasSynthBitfield = val; }
@@ -1393,7 +1399,10 @@
     OBJC_PR_copy      = 0x20,
     OBJC_PR_nonatomic = 0x40,
     OBJC_PR_setter    = 0x80,
-    OBJC_PR_atomic    = 0x100
+    OBJC_PR_atomic    = 0x100,
+    OBJC_PR_weak      = 0x200,
+    OBJC_PR_strong    = 0x400,
+    OBJC_PR_unsafe_unretained = 0x800
   };
 
   enum SetterKind { Assign, Retain, Copy };
@@ -1401,8 +1410,8 @@
 private:
   SourceLocation AtLoc;   // location of @property
   TypeSourceInfo *DeclType;
-  unsigned PropertyAttributes : 9;
-  unsigned PropertyAttributesAsWritten : 9;
+  unsigned PropertyAttributes : 11;
+  unsigned PropertyAttributesAsWritten : 11;
   // @required/@optional
   unsigned PropertyImplementation : 2;
 
@@ -1466,7 +1475,7 @@
   /// the property setter. This is only valid if the property has been
   /// defined to have a setter.
   SetterKind getSetterKind() const {
-    if (PropertyAttributes & OBJC_PR_retain)
+    if (PropertyAttributes & (OBJC_PR_retain|OBJC_PR_strong))
       return Retain;
     if (PropertyAttributes & OBJC_PR_copy)
       return Copy;

Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Wed Jun 15 18:02:42 2011
@@ -2276,6 +2276,8 @@
     case CK_IntegralComplexToReal:
     case CK_IntegralComplexCast:
     case CK_IntegralComplexToFloatingComplex:
+    case CK_ObjCProduceObject:
+    case CK_ObjCConsumeObject:
       assert(!getType()->isBooleanType() && "unheralded conversion to bool");
       // fallthrough to check for null base path
 

Modified: cfe/trunk/include/clang/AST/ExprObjC.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprObjC.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExprObjC.h (original)
+++ cfe/trunk/include/clang/AST/ExprObjC.h Wed Jun 15 18:02:42 2011
@@ -456,7 +456,11 @@
   ///
   /// When non-zero, we have a method declaration; otherwise, we just
   /// have a selector.
-  unsigned HasMethod : 8;
+  unsigned HasMethod : 1;
+
+  /// \brief Whether this message send is a "delegate init call",
+  /// i.e. a call of an init method on self from within an init method.
+  unsigned IsDelegateInitCall : 1;
 
   /// \brief When the message expression is a send to 'super', this is
   /// the location of the 'super' keyword.
@@ -476,7 +480,7 @@
 
   ObjCMessageExpr(EmptyShell Empty, unsigned NumArgs)
     : Expr(ObjCMessageExprClass, Empty), NumArgs(NumArgs), Kind(0), 
-      HasMethod(0), SelectorOrMethod(0) { }
+      HasMethod(0), IsDelegateInitCall(0), SelectorOrMethod(0) { }
 
   ObjCMessageExpr(QualType T, ExprValueKind VK,
                   SourceLocation LBracLoc,
@@ -807,6 +811,12 @@
     getArgs()[Arg] = ArgExpr;
   }
 
+  /// isDelegateInitCall - Answers whether this message send has been
+  /// tagged as a "delegate init call", i.e. a call to a method in the
+  /// -init family on self from within an -init method implementation.
+  bool isDelegateInitCall() const { return IsDelegateInitCall; }
+  void setDelegateInitCall(bool isDelegate) { IsDelegateInitCall = isDelegate; }
+
   SourceLocation getLeftLoc() const { return LBracLoc; }
   SourceLocation getRightLoc() const { return RBracLoc; }
   SourceLocation getSelectorLoc() const { return SelectorLoc; }
@@ -892,6 +902,122 @@
   child_range children() { return child_range(&Base, &Base+1); }
 };
 
+
+/// ObjCIndirectCopyRestoreExpr - Represents the passing of a function
+/// argument by indirect copy-restore in ARC.  This is used to support
+/// passing indirect arguments with the wrong lifetime, e.g. when
+/// passing the address of a __strong local variable to an 'out'
+/// parameter.  This expression kind is only valid in an "argument"
+/// position to some sort of call expression.
+///
+/// The parameter must have type 'pointer to T', and the argument must
+/// have type 'pointer to U', where T and U agree except possibly in
+/// qualification.  If the argument value is null, then a null pointer
+/// is passed;  otherwise it points to an object A, and:
+/// 1. A temporary object B of type T is initialized, either by
+///    zero-initialization (used when initializing an 'out' parameter)
+///    or copy-initialization (used when initializing an 'inout'
+///    parameter).
+/// 2. The address of the temporary is passed to the function.
+/// 3. If the call completes normally, A is move-assigned from B.
+/// 4. Finally, A is destroyed immediately.
+///
+/// Currently 'T' must be a retainable object lifetime and must be
+/// __autoreleasing;  this qualifier is ignored when initializing
+/// the value.
+class ObjCIndirectCopyRestoreExpr : public Expr {
+  Stmt *Operand;
+
+  // unsigned ObjCIndirectCopyRestoreBits.ShouldCopy : 1;
+
+  friend class ASTReader;
+  friend class ASTStmtReader;
+
+  void setShouldCopy(bool shouldCopy) {
+    ObjCIndirectCopyRestoreExprBits.ShouldCopy = shouldCopy;
+  }
+
+  explicit ObjCIndirectCopyRestoreExpr(EmptyShell Empty)
+    : Expr(ObjCIndirectCopyRestoreExprClass, Empty) { }
+
+public:
+  ObjCIndirectCopyRestoreExpr(Expr *operand, QualType type, bool shouldCopy)
+    : Expr(ObjCIndirectCopyRestoreExprClass, type, VK_LValue, OK_Ordinary,
+           operand->isTypeDependent(), operand->isValueDependent(),
+           operand->containsUnexpandedParameterPack()),
+      Operand(operand) {
+    setShouldCopy(shouldCopy);
+  }
+
+  Expr *getSubExpr() { return cast<Expr>(Operand); }
+  const Expr *getSubExpr() const { return cast<Expr>(Operand); }
+
+  /// shouldCopy - True if we should do the 'copy' part of the
+  /// copy-restore.  If false, the temporary will be zero-initialized.
+  bool shouldCopy() const { return ObjCIndirectCopyRestoreExprBits.ShouldCopy; }
+
+  child_range children() { return child_range(&Operand, &Operand+1); }  
+
+  // Source locations are determined by the subexpression.
+  SourceRange getSourceRange() const { return Operand->getSourceRange(); }
+  SourceLocation getExprLoc() const { return getSubExpr()->getExprLoc(); }
+
+  static bool classof(const Stmt *s) {
+    return s->getStmtClass() == ObjCIndirectCopyRestoreExprClass;
+  }
+  static bool classof(const ObjCIndirectCopyRestoreExpr *) { return true; }
+};
+
+/// \brief An Objective-C "bridged" cast expression, which casts between
+/// Objective-C pointers and C pointers, transferring ownership in the process.
+///
+/// \code
+/// NSString *str = (__bridge_transfer NSString *)CFCreateString();
+/// \endcode
+class ObjCBridgedCastExpr : public ExplicitCastExpr {
+  SourceLocation LParenLoc;
+  SourceLocation BridgeKeywordLoc;
+  unsigned Kind : 2;
+  
+  friend class ASTStmtReader;
+  friend class ASTStmtWriter;
+  
+public:
+  ObjCBridgedCastExpr(SourceLocation LParenLoc, ObjCBridgeCastKind Kind,
+                      SourceLocation BridgeKeywordLoc, TypeSourceInfo *TSInfo,
+                      Expr *Operand)
+    : ExplicitCastExpr(ObjCBridgedCastExprClass, TSInfo->getType(), VK_RValue,
+                       CK_BitCast, Operand, 0, TSInfo),
+      LParenLoc(LParenLoc), BridgeKeywordLoc(BridgeKeywordLoc), Kind(Kind) { }
+  
+  /// \brief Construct an empty Objective-C bridged cast.
+  explicit ObjCBridgedCastExpr(EmptyShell Shell)
+    : ExplicitCastExpr(ObjCBridgedCastExprClass, Shell, 0) { }
+
+  SourceLocation getLParenLoc() const { return LParenLoc; }
+
+  /// \brief Determine which kind of bridge is being performed via this cast.
+  ObjCBridgeCastKind getBridgeKind() const { 
+    return static_cast<ObjCBridgeCastKind>(Kind); 
+  }
+  
+  /// \brief Retrieve the kind of bridge being performed as a string.
+  llvm::StringRef getBridgeKindName() const;
+  
+  /// \brief The location of the bridge keyword.
+  SourceLocation getBridgeKeywordLoc() const { return BridgeKeywordLoc; }
+  
+  SourceRange getSourceRange() const {
+    return SourceRange(LParenLoc, getSubExpr()->getLocEnd());
+  }
+  
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == ObjCBridgedCastExprClass;
+  }
+  static bool classof(const ObjCBridgedCastExpr *) { return true; }
+ 
+};
+  
 }  // end namespace clang
 
 #endif

Modified: cfe/trunk/include/clang/AST/OperationKinds.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/OperationKinds.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/OperationKinds.h (original)
+++ cfe/trunk/include/clang/AST/OperationKinds.h Wed Jun 15 18:02:42 2011
@@ -245,7 +245,17 @@
 
   /// \brief Converts from an integral complex to a floating complex.
   ///   _Complex unsigned -> _Complex float
-  CK_IntegralComplexToFloatingComplex
+  CK_IntegralComplexToFloatingComplex,
+
+  /// \brief Produces an Objective-C object so that it may be
+  /// consumed, e.g. by being passed to a consuming parameter.  Calls
+  /// objc_retain.
+  CK_ObjCProduceObject,
+
+  /// \brief Consumes an Objective-C object that has just been
+  /// produced, e.g. as the return value of a retaining call.  Enters
+  /// a cleanup to call objc_release at some indefinite time.
+  CK_ObjCConsumeObject
 };
 
 #define CK_Invalid ((CastKind) -1)
@@ -284,6 +294,19 @@
   UO_Extension            // __extension__ marker.
 };
 
+/// \brief The kind of bridging performed by the Objective-C bridge cast.
+enum ObjCBridgeCastKind {
+  /// \brief Bridging via __bridge, which does nothing but reinterpret
+  /// the bits.
+  OBC_Bridge,
+  /// \brief Bridging via __bridge_transfer, which transfers ownership of an
+  /// Objective-C pointer into ARC.
+  OBC_BridgeTransfer,
+  /// \brief Bridging via __bridge_retain, which makes an ARC object available
+  /// as a +1 C pointer.
+  OBC_BridgeRetained
+};
+
 }
 
 #endif

Modified: cfe/trunk/include/clang/AST/ParentMap.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ParentMap.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ParentMap.h (original)
+++ cfe/trunk/include/clang/AST/ParentMap.h Wed Jun 15 18:02:42 2011
@@ -32,6 +32,7 @@
   Stmt *getParent(Stmt*) const;
   Stmt *getParentIgnoreParens(Stmt *) const;
   Stmt *getParentIgnoreParenCasts(Stmt *) const;
+  Stmt *getOuterParenParent(Stmt *) const;
 
   const Stmt *getParent(const Stmt* S) const {
     return getParent(const_cast<Stmt*>(S));

Modified: cfe/trunk/include/clang/AST/PrettyPrinter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/PrettyPrinter.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/PrettyPrinter.h (original)
+++ cfe/trunk/include/clang/AST/PrettyPrinter.h Wed Jun 15 18:02:42 2011
@@ -41,7 +41,7 @@
       SuppressTagKeyword(false), SuppressTag(false), SuppressScope(false),
       SuppressInitializers(false),
       Dump(false), ConstantArraySizeAsWritten(false),
-      AnonymousTagLocations(true) { }
+      AnonymousTagLocations(true), SuppressStrongLifetime(false) { }
 
   /// \brief The number of spaces to use to indent each line.
   unsigned Indentation : 8;
@@ -129,6 +129,10 @@
   /// that entity (e.g., "enum <anonymous at t.h:10:5>"). Otherwise, just 
   /// prints "<anonymous>" for the name.
   bool AnonymousTagLocations : 1;
+  
+  /// \brief When true, suppress printing of the __strong lifetime qualifier in
+  /// ARC.
+  unsigned SuppressStrongLifetime : 1;
 };
 
 } // end namespace clang

Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Wed Jun 15 18:02:42 2011
@@ -1721,6 +1721,7 @@
 DEF_TRAVERSE_STMT(ObjCAtThrowStmt, { })
 DEF_TRAVERSE_STMT(ObjCAtTryStmt, { })
 DEF_TRAVERSE_STMT(ObjCForCollectionStmt, { })
+DEF_TRAVERSE_STMT(ObjCAutoreleasePoolStmt, { })
 DEF_TRAVERSE_STMT(CXXForRangeStmt, { })
 DEF_TRAVERSE_STMT(ReturnStmt, { })
 DEF_TRAVERSE_STMT(SwitchStmt, { })
@@ -1933,6 +1934,10 @@
 DEF_TRAVERSE_STMT(ObjCPropertyRefExpr, { })
 DEF_TRAVERSE_STMT(ObjCProtocolExpr, { })
 DEF_TRAVERSE_STMT(ObjCSelectorExpr, { })
+DEF_TRAVERSE_STMT(ObjCIndirectCopyRestoreExpr, { })
+DEF_TRAVERSE_STMT(ObjCBridgedCastExpr, {
+  TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc()));
+})
 DEF_TRAVERSE_STMT(ParenExpr, { })
 DEF_TRAVERSE_STMT(ParenListExpr, { })
 DEF_TRAVERSE_STMT(PredefinedExpr, { })

Modified: cfe/trunk/include/clang/AST/Stmt.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Stmt.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Stmt.h (original)
+++ cfe/trunk/include/clang/AST/Stmt.h Wed Jun 15 18:02:42 2011
@@ -183,6 +183,13 @@
     unsigned NumPreArgs : 1;
   };
 
+  class ObjCIndirectCopyRestoreExprBitfields {
+    friend class ObjCIndirectCopyRestoreExpr;
+    unsigned : NumExprBits;
+
+    unsigned ShouldCopy : 1;
+  };
+
   union {
     // FIXME: this is wasteful on 64-bit platforms.
     void *Aligner;
@@ -193,6 +200,7 @@
     DeclRefExprBitfields DeclRefExprBits;
     CastExprBitfields CastExprBits;
     CallExprBitfields CallExprBits;
+    ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits;
   };
 
   friend class ASTStmtReader;

Modified: cfe/trunk/include/clang/AST/StmtObjC.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/StmtObjC.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/StmtObjC.h (original)
+++ cfe/trunk/include/clang/AST/StmtObjC.h Wed Jun 15 18:02:42 2011
@@ -342,6 +342,39 @@
   child_range children() { return child_range(&Throw, &Throw+1); }
 };
 
+/// ObjCAutoreleasePoolStmt - This represent objective-c's 
+/// @autoreleasepool Statement
+class ObjCAutoreleasePoolStmt : public Stmt {
+  Stmt *SubStmt;
+  SourceLocation AtLoc;
+public:
+  ObjCAutoreleasePoolStmt(SourceLocation atLoc, 
+                            Stmt *subStmt)
+  : Stmt(ObjCAutoreleasePoolStmtClass),
+    SubStmt(subStmt), AtLoc(atLoc) {}
+
+  explicit ObjCAutoreleasePoolStmt(EmptyShell Empty) :
+    Stmt(ObjCAutoreleasePoolStmtClass, Empty) { }
+
+  const Stmt *getSubStmt() const { return SubStmt; }
+  Stmt *getSubStmt() { return SubStmt; }
+  void setSubStmt(Stmt *S) { SubStmt = S; }
+
+  SourceRange getSourceRange() const {
+    return SourceRange(AtLoc, SubStmt->getLocEnd());
+  }
+
+  SourceLocation getAtLoc() const { return AtLoc; }
+  void setAtLoc(SourceLocation Loc) { AtLoc = Loc; }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == ObjCAutoreleasePoolStmtClass;
+  }
+  static bool classof(const ObjCAutoreleasePoolStmt *) { return true; }
+
+  child_range children() { return child_range(&SubStmt, &SubStmt + 1); }
+};
+
 }  // end namespace clang
 
 #endif

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Wed Jun 15 18:02:42 2011
@@ -126,6 +126,28 @@
     Strong
   };
 
+  enum ObjCLifetime {
+    /// There is no lifetime qualification on this type.
+    OCL_None,
+
+    /// This object can be modified without requiring retains or
+    /// releases.
+    OCL_ExplicitNone,
+
+    /// Assigning into this object requires the old value to be
+    /// released and the new value to be retained.  The timing of the
+    /// release of the old value is inexact: it may be moved to
+    /// immediately after the last known point where the value is
+    /// live.
+    OCL_Strong,
+
+    /// Reading or writing from this object requires a barrier call.
+    OCL_Weak,
+
+    /// Assigning into this object requires a lifetime extension.
+    OCL_Autoreleasing
+  };
+
   enum {
     /// The maximum supported address space number.
     /// 24 bits should be enough for anyone.
@@ -218,7 +240,37 @@
     qs.removeObjCGCAttr();
     return qs;
   }
+  Qualifiers withoutObjCGLifetime() const {
+    Qualifiers qs = *this;
+    qs.removeObjCLifetime();
+    return qs;
+  }
+
+  bool hasObjCLifetime() const { return Mask & LifetimeMask; }
+  ObjCLifetime getObjCLifetime() const {
+    return ObjCLifetime((Mask & LifetimeMask) >> LifetimeShift);
+  }
+  void setObjCLifetime(ObjCLifetime type) {
+    Mask = (Mask & ~LifetimeMask) | (type << LifetimeShift);
+  }
+  void removeObjCLifetime() { setObjCLifetime(OCL_None); }
+  void addObjCLifetime(ObjCLifetime type) {
+    assert(type);
+    setObjCLifetime(type);
+  }
+
+  /// True if the lifetime is neither None or ExplicitNone.
+  bool hasNonTrivialObjCLifetime() const {
+    ObjCLifetime lifetime = getObjCLifetime();
+    return (lifetime > OCL_ExplicitNone);
+  }
 
+  /// True if the lifetime is either strong or weak.
+  bool hasStrongOrWeakObjCLifetime() const {
+    ObjCLifetime lifetime = getObjCLifetime();
+    return (lifetime == OCL_Strong || lifetime == OCL_Weak);
+  }
+  
   bool hasAddressSpace() const { return Mask & AddressSpaceMask; }
   unsigned getAddressSpace() const { return Mask >> AddressSpaceShift; }
   void setAddressSpace(unsigned space) {
@@ -277,6 +329,8 @@
         addAddressSpace(Q.getAddressSpace());
       if (Q.hasObjCGCAttr())
         addObjCGCAttr(Q.getObjCGCAttr());
+      if (Q.hasObjCLifetime())
+        addObjCLifetime(Q.getObjCLifetime());
     }
   }
 
@@ -287,6 +341,8 @@
            !hasAddressSpace() || !qs.hasAddressSpace());
     assert(getObjCGCAttr() == qs.getObjCGCAttr() ||
            !hasObjCGCAttr() || !qs.hasObjCGCAttr());
+    assert(getObjCLifetime() == qs.getObjCLifetime() ||
+           !hasObjCLifetime() || !qs.hasObjCLifetime());
     Mask |= qs.Mask;
   }
 
@@ -301,10 +357,30 @@
       // changed.
       (getObjCGCAttr() == other.getObjCGCAttr() ||
        !hasObjCGCAttr() || !other.hasObjCGCAttr()) &&
+      // ObjC lifetime qualifiers must match exactly.
+      getObjCLifetime() == other.getObjCLifetime() &&
       // CVR qualifiers may subset.
       (((Mask & CVRMask) | (other.Mask & CVRMask)) == (Mask & CVRMask));
   }
 
+  /// \brief Determines if these qualifiers compatibly include another set of
+  /// qualifiers from the narrow perspective of Objective-C ARC lifetime.
+  ///
+  /// One set of Objective-C lifetime qualifiers compatibly includes the other
+  /// if the lifetime qualifiers match, or if both are non-__weak and the 
+  /// including set also contains the 'const' qualifier.
+  bool compatiblyIncludesObjCLifetime(Qualifiers other) const {
+    if (getObjCLifetime() == other.getObjCLifetime())
+      return true;
+    
+    if (getObjCLifetime() == OCL_Weak || other.getObjCLifetime() == OCL_Weak)
+      return false;
+    
+    return hasConst();
+  }
+  
+  bool isSupersetOf(Qualifiers Other) const;
+
   /// \brief Determine whether this set of qualifiers is a strict superset of
   /// another set of qualifiers, not considering qualifier compatibility.
   bool isStrictSupersetOf(Qualifiers Other) const;
@@ -351,14 +427,16 @@
 
 private:
 
-  // bits:     |0 1 2|3 .. 4|5  ..  31|
-  //           |C R V|GCAttr|AddrSpace|
+  // bits:     |0 1 2|3 .. 4|5  ..  7|8   ...   31|
+  //           |C R V|GCAttr|Lifetime|AddressSpace|
   uint32_t Mask;
 
   static const uint32_t GCAttrMask = 0x18;
   static const uint32_t GCAttrShift = 3;
-  static const uint32_t AddressSpaceMask = ~(CVRMask | GCAttrMask);
-  static const uint32_t AddressSpaceShift = 5;
+  static const uint32_t LifetimeMask = 0xE0;
+  static const uint32_t LifetimeShift = 5;
+  static const uint32_t AddressSpaceMask = ~(CVRMask|GCAttrMask|LifetimeMask);
+  static const uint32_t AddressSpaceShift = 8;
 };
 
 /// CallingConv - Specifies the calling convention that a function uses.
@@ -527,6 +605,23 @@
     return QualType::isConstant(*this, Ctx);
   }
 
+  /// \brief Determine whether this is a Plain Old Data (POD) type (C++ 3.9p10).
+  bool isPODType(ASTContext &Context) const;
+
+  /// isCXX11PODType() - Return true if this is a POD type according to the
+  /// more relaxed rules of the C++11 standard, regardless of the current
+  /// compilation's language.
+  /// (C++0x [basic.types]p9)
+  bool isCXX11PODType(ASTContext &Context) const;
+  
+  /// isTrivialType - Return true if this is a trivial type
+  /// (C++0x [basic.types]p9)
+  bool isTrivialType(ASTContext &Context) const;  
+
+  /// isTriviallyCopyableType - Return true if this is a trivially
+  /// copyable type (C++0x [basic.types]p9)
+  bool isTriviallyCopyableType(ASTContext &Context) const;
+
   // Don't promise in the API that anything besides 'const' can be
   // easily added.
 
@@ -709,7 +804,7 @@
   /// getAddressSpace - Return the address space of this type.
   inline unsigned getAddressSpace() const;
 
-  /// GCAttrTypesAttr - Returns gc attribute of this type.
+  /// getObjCGCAttr - Returns gc attribute of this type.
   inline Qualifiers::GC getObjCGCAttr() const;
 
   /// isObjCGCWeak true when Type is objc's weak.
@@ -722,9 +817,24 @@
     return getObjCGCAttr() == Qualifiers::Strong;
   }
 
+  /// getObjCLifetime - Returns lifetime attribute of this type.
+  Qualifiers::ObjCLifetime getObjCLifetime() const {
+    return getQualifiers().getObjCLifetime();
+  }
+
+  bool hasNonTrivialObjCLifetime() const {
+    return getQualifiers().hasNonTrivialObjCLifetime();
+  }
+
+  bool hasStrongOrWeakObjCLifetime() const {
+    return getQualifiers().hasStrongOrWeakObjCLifetime();
+  }
+
   enum DestructionKind {
     DK_none,
-    DK_cxx_destructor
+    DK_cxx_destructor,
+    DK_objc_strong_lifetime,
+    DK_objc_weak_lifetime
   };
 
   /// isDestructedType - nonzero if objects of this type require
@@ -735,6 +845,9 @@
     return isDestructedTypeImpl(*this);
   }
 
+  /// \brief Determine whether this type has trivial copy-assignment semantics.
+  bool hasTrivialCopyAssignment(ASTContext &Context) const;
+  
 private:
   // These methods are implemented in a separate translation unit;
   // "static"-ize them to avoid creating temporary QualTypes in the
@@ -849,6 +962,11 @@
   bool hasObjCGCAttr() const { return Quals.hasObjCGCAttr(); }
   Qualifiers::GC getObjCGCAttr() const { return Quals.getObjCGCAttr(); }
 
+  bool hasObjCLifetime() const { return Quals.hasObjCLifetime(); }
+  Qualifiers::ObjCLifetime getObjCLifetime() const {
+    return Quals.getObjCLifetime();
+  }
+
   bool hasAddressSpace() const { return Quals.hasAddressSpace(); }
   unsigned getAddressSpace() const { return Quals.getAddressSpace(); }
 
@@ -1005,7 +1123,7 @@
 
     /// Extra information which affects how the function is called, like
     /// regparm and the calling convention.
-    unsigned ExtInfo : 8;
+    unsigned ExtInfo : 9;
 
     /// Whether the function is variadic.  Only used by FunctionProtoType.
     unsigned Variadic : 1;
@@ -1186,31 +1304,14 @@
     return !isReferenceType() && !isFunctionType() && !isVoidType();
   }
 
-  /// isPODType - Return true if this is a plain-old-data type (C++ 3.9p10).
-  bool isPODType() const;
-
   /// isLiteralType - Return true if this is a literal type
   /// (C++0x [basic.types]p10)
   bool isLiteralType() const;
 
-  /// isTrivialType - Return true if this is a trivial type
-  /// (C++0x [basic.types]p9)
-  bool isTrivialType() const;
-
-  /// isTriviallyCopyableType - Return true if this is a trivially copyable type
-  /// (C++0x [basic.types]p9
-  bool isTriviallyCopyableType() const;
-
   /// \brief Test if this type is a standard-layout type.
   /// (C++0x [basic.type]p9)
   bool isStandardLayoutType() const;
 
-  /// isCXX11PODType() - Return true if this is a POD type according to the
-  /// more relaxed rules of the C++11 standard, regardless of the current
-  /// compilation's language.
-  /// (C++0x [basic.types]p9)
-  bool isCXX11PODType() const;
-
   /// Helper methods to distinguish type categories. All type predicates
   /// operate on the canonical type, ignoring typedefs and qualifiers.
 
@@ -1290,7 +1391,11 @@
   bool isComplexIntegerType() const;            // GCC _Complex integer type.
   bool isVectorType() const;                    // GCC vector type.
   bool isExtVectorType() const;                 // Extended vector type.
-  bool isObjCObjectPointerType() const;         // Pointer to *any* ObjC object.
+  bool isObjCObjectPointerType() const;         // pointer to ObjC object
+  bool isObjCRetainableType() const;            // ObjC object or block pointer
+  bool isObjCLifetimeType() const;              // (array of)* retainable type
+  bool isObjCIndirectLifetimeType() const;      // (pointer to)* lifetime type
+  bool isObjCNSObjectType() const;              // __attribute__((NSObject))
   // FIXME: change this to 'raw' interface type, so we can used 'interface' type
   // for the common case.
   bool isObjCObjectType() const;                // NSString or typeof(*(id)0)
@@ -1302,9 +1407,19 @@
   bool isObjCClassType() const;                 // Class
   bool isObjCSelType() const;                 // Class
   bool isObjCBuiltinType() const;               // 'id' or 'Class'
+  bool isObjCARCBridgableType() const;
+  bool isCARCBridgableType() const;
   bool isTemplateTypeParmType() const;          // C++ template type parameter
   bool isNullPtrType() const;                   // C++0x nullptr_t
 
+  /// Determines if this type, which must satisfy
+  /// isObjCLifetimeType(), is implicitly __unsafe_unretained rather
+  /// than implicitly __strong.
+  bool isObjCARCImplicitlyUnretainedType() const;
+
+  /// Return the implicit lifetime for this type, which must not be dependent.
+  Qualifiers::ObjCLifetime getObjCARCImplicitLifetime() const;
+
   enum ScalarTypeKind {
     STK_Pointer,
     STK_MemberPointer,
@@ -1480,6 +1595,7 @@
   }
   CanQualType getCanonicalTypeUnqualified() const; // in CanonicalType.h
   void dump() const;
+
   static bool classof(const Type *) { return true; }
 
   friend class ASTReader;
@@ -2340,30 +2456,33 @@
   // * AST read and write
   // * Codegen
   class ExtInfo {
-    // Feel free to rearrange or add bits, but if you go over 8,
+    // Feel free to rearrange or add bits, but if you go over 9,
     // you'll need to adjust both the Bits field below and
     // Type::FunctionTypeBitfields.
 
-    //   |  CC  |noreturn|hasregparm|regparm
-    //   |0 .. 2|   3    |    4     |5 ..  7
+    //   |  CC  |noreturn|produces|hasregparm|regparm
+    //   |0 .. 2|   3    |    4   |    5     |6 ..  8
     enum { CallConvMask = 0x7 };
     enum { NoReturnMask = 0x8 };
-    enum { HasRegParmMask = 0x10 };
-    enum { RegParmMask = ~(CallConvMask | NoReturnMask),
-           RegParmOffset = 5 };
+    enum { ProducesResultMask = 0x10 };
+    enum { HasRegParmMask = 0x20 };
+    enum { RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask),
+           RegParmOffset = 6 }; // Assumed to be the last field
 
-    unsigned char Bits;
+    uint16_t Bits;
 
-    ExtInfo(unsigned Bits) : Bits(static_cast<unsigned char>(Bits)) {}
+    ExtInfo(unsigned Bits) : Bits(static_cast<uint16_t>(Bits)) {}
 
     friend class FunctionType;
 
    public:
     // Constructor with no defaults. Use this when you know that you
     // have all the elements (when reading an AST file for example).
-    ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc) {
+    ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc,
+            bool producesResult) {
       Bits = ((unsigned) cc) |
              (noReturn ? NoReturnMask : 0) |
+             (producesResult ? ProducesResultMask : 0) |
              (hasRegParm ? HasRegParmMask : 0) |
              (regParm << RegParmOffset);
     }
@@ -2373,6 +2492,7 @@
     ExtInfo() : Bits(0) {}
 
     bool getNoReturn() const { return Bits & NoReturnMask; }
+    bool getProducesResult() const { return Bits & ProducesResultMask; }
     bool getHasRegParm() const { return Bits & HasRegParmMask; }
     unsigned getRegParm() const { return Bits >> RegParmOffset; }
     CallingConv getCC() const { return CallingConv(Bits & CallConvMask); }
@@ -2394,8 +2514,17 @@
         return ExtInfo(Bits & ~NoReturnMask);
     }
 
+    ExtInfo withProducesResult(bool producesResult) const {
+      if (producesResult)
+        return ExtInfo(Bits | ProducesResultMask);
+      else
+        return ExtInfo(Bits & ~ProducesResultMask);
+    }
+
     ExtInfo withRegParm(unsigned RegParm) const {
-      return ExtInfo(HasRegParmMask | (Bits & ~RegParmMask) | (RegParm << RegParmOffset));
+      return ExtInfo((Bits & ~RegParmMask) |
+                     (HasRegParmMask) |
+                     (RegParm << RegParmOffset));
     }
 
     ExtInfo withCallingConv(CallingConv cc) const {
@@ -2495,7 +2624,8 @@
   struct ExtProtoInfo {
     ExtProtoInfo() :
       Variadic(false), ExceptionSpecType(EST_None), TypeQuals(0),
-      RefQualifier(RQ_None), NumExceptions(0), Exceptions(0), NoexceptExpr(0) {}
+      RefQualifier(RQ_None), NumExceptions(0), Exceptions(0), NoexceptExpr(0),
+      ConsumedArguments(0) {}
 
     FunctionType::ExtInfo ExtInfo;
     bool Variadic;
@@ -2505,6 +2635,7 @@
     unsigned NumExceptions;
     const QualType *Exceptions;
     Expr *NoexceptExpr;
+    const bool *ConsumedArguments;
   };
 
 private:
@@ -2523,7 +2654,7 @@
                     QualType canonical, const ExtProtoInfo &epi);
 
   /// NumArgs - The number of arguments this function has, not counting '...'.
-  unsigned NumArgs : 20;
+  unsigned NumArgs : 19;
 
   /// NumExceptions - The number of types in the exception spec, if any.
   unsigned NumExceptions : 9;
@@ -2531,6 +2662,9 @@
   /// ExceptionSpecType - The type of exception specification this function has.
   unsigned ExceptionSpecType : 3;
 
+  /// HasAnyConsumedArgs - Whether this function has any consumed arguments.
+  unsigned HasAnyConsumedArgs : 1;
+
   /// ArgInfo - There is an variable size array after the class in memory that
   /// holds the argument types.
 
@@ -2540,8 +2674,25 @@
   /// NoexceptExpr - Instead of Exceptions, there may be a single Expr* pointing
   /// to the expression in the noexcept() specifier.
 
+  /// ConsumedArgs - A variable size array, following Exceptions
+  /// and of length NumArgs, holding flags indicating which arguments
+  /// are consumed.  This only appears if HasAnyConsumedArgs is true.
+
   friend class ASTContext;  // ASTContext creates these.
 
+  const bool *getConsumedArgsBuffer() const {
+    assert(hasAnyConsumedArgs());
+
+    // Find the end of the exceptions.
+    Expr * const *eh_end = reinterpret_cast<Expr * const *>(arg_type_end());
+    if (getExceptionSpecType() != EST_ComputedNoexcept)
+      eh_end += NumExceptions;
+    else
+      eh_end += 1; // NoexceptExpr
+
+    return reinterpret_cast<const bool*>(eh_end);
+  }
+
 public:
   unsigned getNumArgs() const { return NumArgs; }
   QualType getArgType(unsigned i) const {
@@ -2562,6 +2713,8 @@
     } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
       EPI.NoexceptExpr = getNoexceptExpr();
     }
+    if (hasAnyConsumedArgs())
+      EPI.ConsumedArguments = getConsumedArgsBuffer();
     return EPI;
   }
 
@@ -2647,6 +2800,16 @@
     return exception_begin() + NumExceptions;
   }
 
+  bool hasAnyConsumedArgs() const {
+    return HasAnyConsumedArgs;
+  }
+  bool isArgConsumed(unsigned I) const {
+    assert(I < getNumArgs() && "argument index out of range!");
+    if (hasAnyConsumedArgs())
+      return getConsumedArgsBuffer()[I];
+    return false;
+  }
+
   bool isSugared() const { return false; }
   QualType desugar() const { return QualType(this, 0); }
 
@@ -2971,6 +3134,7 @@
 
     // Enumerated operand (string or keyword).
     attr_objc_gc,
+    attr_objc_lifetime,
     attr_pcs,
 
     FirstEnumOperandKind = attr_objc_gc,

Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Wed Jun 15 18:02:42 2011
@@ -400,6 +400,11 @@
   let Spellings = ["NSObject"];
 }
 
+def ObjCPreciseLifetime : Attr {
+  let Spellings = ["objc_precise_lifetime"];
+  let Subjects = [Var];
+}
+
 def Overloadable : Attr {
   let Spellings = ["overloadable"];
 }

Modified: cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td Wed Jun 15 18:02:42 2011
@@ -32,6 +32,7 @@
 def note_matching : Note<"to match this '%0'">;
 
 def note_using : Note<"using">;
+def note_possibility : Note<"one possibility">;
 def note_also_found : Note<"also found">;
 
 // Parse && Lex

Modified: cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td Wed Jun 15 18:02:42 2011
@@ -82,6 +82,10 @@
   "conflicting deployment targets, both '%0' and '%1' are present in environment">;
 def err_drv_invalid_arch_for_deployment_target : Error<
   "invalid architecture '%0' for deployment target '%1'">;
+def err_drv_objc_gc_arr : Error<
+  "cannot specify both '-fobjc-arc' and '%0'">;
+def err_arc_nonfragile_abi : Error<
+  "-fobjc-arc is not supported with fragile abi">;
 
 def warn_c_kext : Warning<
   "ignoring -fapple-kext which is valid for c++ and objective-c++ only">;

Modified: cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td Wed Jun 15 18:02:42 2011
@@ -137,6 +137,9 @@
     "PCH file was compiled with the %select{32-bit|enhanced non-fragile}0 "
     "Objective-C ABI but the %select{32-bit|enhanced non-fragile}1 "
     "Objective-C ABI is selected">;
+def warn_pch_auto_ref_count : Error<
+    "PCH file was compiled %select{without|with} automated reference counting,"
+    "which is currently %select{disabled|enabled}">;
 def warn_pch_apple_kext : Error<
     "PCH file was compiled %select{with|without}0 support for Apple's kernel "
     "extensions ABI but it is currently %select{disabled|enabled}1">;

Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Wed Jun 15 18:02:42 2011
@@ -169,6 +169,8 @@
 def CustomAtomic : DiagGroup<"custom-atomic-properties">;
 def AtomicProperties : DiagGroup<"atomic-properties",
                                  [ImplicitAtomic, CustomAtomic]>;
+def AutomaticReferenceCountingABI : DiagGroup<"arc-abi">;
+def AutomaticReferenceCounting : DiagGroup<"arc", [AutomaticReferenceCountingABI]>;
 def Selector : DiagGroup<"selector">;
 def NonfragileAbi2 : DiagGroup<"nonfragile-abi2">;
 def Protocol : DiagGroup<"protocol">;

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Jun 15 18:02:42 2011
@@ -430,6 +430,12 @@
 def warn_atomic_property_rule : Warning<
   "writable atomic property %0 cannot pair a synthesized setter/getter "
   "with a user defined setter/getter">;
+def warn_ownin_getter_rule : Warning<
+  "property's synthesized getter follows Cocoa naming"
+  " convention for returning 'owned' objects">;
+def err_ownin_getter_rule : Error<
+  "property's synthesized getter follows Cocoa naming"
+  " convention for returning 'owned' objects">;
 def warn_default_atomic_custom_getter_setter : Warning<
   "atomic by default property %0 has a user defined %select{getter|setter}1 "
   "(property should be marked 'atomic' if this is intended)">,
@@ -465,6 +471,8 @@
 def error_missing_property_ivar_decl : Error<
   "synthesized property %0 must either be named the same as a compatible"
   " ivar or must explicitly name an ivar">;
+def error_synthesize_weak_non_arc_or_gc : Error<
+  "@synthesize of 'weak' property is only allowed in ARC or GC mode">;
 
 def error_synthesized_ivar_yet_not_supported : Error<
   "instance variable synthesis not yet supported"
@@ -477,7 +485,7 @@
 def error_weak_property : Error<
   "existing ivar %1 for __weak property %0 must be __weak">;
 def error_strong_property : Error<
-  "property %0 must be declared __weak to match existing ivar %1 with __weak attribute">;
+  "existing ivar %1 for strong property %0 may not be __weak">;
 def error_dynamic_property_ivar_decl : Error<
   "dynamic property can not have ivar specification">;
 def error_duplicate_ivar_use : Error<
@@ -1138,6 +1146,8 @@
   "format attribute cannot specify the implicit this argument as the format "
   "string">;
 def warn_unknown_method_family : Warning<"unrecognized method family">;
+def err_init_method_bad_return_type : Error<
+  "init methods must return an object pointer type, not %0">;
 def err_attribute_invalid_size : Error<
   "vector size not an integral multiple of component size">;
 def err_attribute_zero_size : Error<"zero vector size">;
@@ -1163,6 +1173,10 @@
   "automatic variable qualified with an address space">;
 def err_arg_with_address_space : Error<
   "parameter may not be qualified with an address space">;
+def err_attr_objc_lifetime_bad_type : Error<
+  "the type %0 cannot be retained">;
+def err_attr_objc_lifetime_redundant : Error<
+  "the type %0 already has retainment attributes set on it">;
 def err_attribute_not_string : Error<
   "argument to %0 attribute was not a string literal">;
 def err_attribute_section_invalid_for_target : Error<
@@ -1235,6 +1249,13 @@
 def err_regparm_mismatch : Error<"function declared with with regparm(%0) "
   "attribute was previously declared "
   "%plural{0:without the regparm|:with the regparm(%1)}1 attribute">;
+def err_objc_precise_lifetime_bad_type : Error<
+  "objc_precise_lifetime only applies to retainable types; type here is %0">;
+def warn_objc_precise_lifetime_meaningless : Error<
+  "objc_precise_lifetime is not meaningful for "
+  "%select{__unsafe_unretained|__autoreleasing}0 objects">;
+def warn_label_attribute_not_unused : Warning<
+  "The only valid attribute for labels is 'unused'">;
 def err_invalid_pcs : Error<"Invalid PCS type">;
 
 // Availability attribute
@@ -1569,6 +1590,17 @@
     "constructor (inherited)}0%1 not viable: "
     "%select{%ordinal6|'this'}5 argument (%2) has %select{no|__weak|__strong}3 "
     "lifetime, but parameter has %select{no|__weak|__strong}4 lifetime">;
+def note_ovl_candidate_bad_lifetime : Note<"candidate "
+    "%select{function|function|constructor|"
+    "function |function |constructor |"
+    "constructor (the implicit default constructor)|"
+    "constructor (the implicit copy constructor)|"
+    "function (the implicit copy assignment operator)|"
+    "constructor (inherited)}0%1 not viable: "
+    "%select{%ordinal6|'this'}5 argument (%2) has "
+    "%select{no|__unsafe_unretained|__strong|__weak|__autoreleasing}3 lifetime,"
+    " but parameter has %select{no|__unsafe_unretained|__strong|__weak|"
+    "__autoreleasing}4 lifetime">;
 def note_ovl_candidate_bad_cvr_this : Note<"candidate "
     "%select{|function|||function||||"
     "function (the implicit copy assignment operator)|}0 not viable: "
@@ -2202,8 +2234,8 @@
 def warn_unavailable_fwdclass_message : Warning<
     "%0 maybe unavailable because receiver type is unknown">;
 def note_unavailable_here : Note<
-  "function has been explicitly marked "
-  "%select{unavailable|deleted|deprecated}0 here">;
+  "%select{declaration|function}0 has been explicitly marked "
+  "%select{unavailable|deleted|deprecated}1 here">;
 def warn_not_enough_argument : Warning<
   "not enough variable arguments in %0 declaration to fit a sentinel">;
 def warn_missing_sentinel : Warning <
@@ -2439,12 +2471,16 @@
   "jump bypasses initialization of @finally block">;
 def note_protected_by_objc_synchronized : Note<
   "jump bypasses initialization of @synchronized block">;
+def note_protected_by_objc_autoreleasepool : Note<
+  "jump bypasses auto release push of @autoreleasepool block">;
 def note_protected_by_cxx_try : Note<
   "jump bypasses initialization of try block">;
 def note_protected_by_cxx_catch : Note<
   "jump bypasses initialization of catch block">;
 def note_protected_by___block : Note<
   "jump bypasses setup of __block variable">;
+def note_protected_by_objc_lifetime : Note<
+  "jump bypasses initialization of retaining variable">;
 
 def note_exits_cleanup : Note<
   "jump exits scope of variable with __attribute__((cleanup))">;
@@ -2464,6 +2500,10 @@
   "jump exits try block">;
 def note_exits_cxx_catch : Note<
   "jump exits catch block">;
+def note_exits_objc_autoreleasepool : Note<
+  "jump exits autoreleasepool block">;
+def note_exits_objc_lifetime : Note<
+  "jump exits scope of retaining variable">;
 
 def err_func_returning_array_function : Error<
   "function cannot return %select{array|function}0 type %1">;
@@ -2495,6 +2535,139 @@
 def ext_flexible_array_union_gnu : Extension<
   "flexible array member %0 in a union is a GNU extension">, InGroup<GNU>;
 
+let CategoryName = "Automatic Reference Counting Issue" in {
+
+// ARC-mode diagnostics.
+def err_arc_weak_no_runtime : Error<
+  "the current deployment target does not support automated __weak references">;
+def err_arc_illegal_explicit_message : Error<
+  "ARC forbids explicit message send of %0">;
+def err_arc_unused_init_message : Error<
+  "the result of a delegate init call must be immediately returned "
+  "or assigned to 'self'">;
+def err_arc_mismatched_cast : Error<
+  "%select{implicit conversion|cast}0 of "
+  "%select{%2|a non-Objective-C pointer type %2|a block pointer|"
+  "an Objective-C pointer|an indirect pointer to an Objective-C pointer}1"
+  " to %3 is disallowed with ARC">;
+def err_arc_objc_object_in_struct : Error<
+  "ARC forbids Objective-C objects in structs or unions">;
+def err_arc_objc_property_default_assign_on_object : Error<
+  "ARC forbids properties of Objective-C objects "
+  "with unspecified storage attribute">;
+def err_arc_illegal_selector : Error<
+  "ARC forbids use of %0 in a @selector">;
+def err_arc_illegal_method_def : Error<
+  "ARC forbids implementation of %0">;
+def err_arc_lost_method_convention : Error<
+  "method was declared as %select{an 'alloc'|a 'copy'|an 'init'|a 'new'}0 "
+  "method, but its implementation doesn't match because %select{"
+  "its result type is not an object pointer|"
+  "its result type is unrelated to its receiver type}1">;
+def note_arc_lost_method_convention : Note<"declaration in interface">;
+def err_arc_gained_method_convention : Error<
+  "method implementation does not match its declaration">;
+def note_arc_gained_method_convention : Note<
+  "declaration in interface is not in the '%select{alloc|copy|init|new}0' "
+  "family because %select{its result type is not an object pointer|"
+  "its result type is unrelated to its receiver type}1">;
+def err_typecheck_arr_assign_self : Error<
+  "cannot assign to 'self' outside of a method in the init family">;
+def err_typecheck_arr_assign_enumeration : Error<
+  "fast enumeration variables can't be modified in ARC by default; "
+  "declare the variable __strong to allow this">;
+def warn_arc_non_pod_class_with_object_member : Warning<
+  "%0 cannot be shared between ARC and non-ARC "
+  "code; add a copy constructor, a copy assignment operator, and a destructor "
+  "to make it ABI-compatible">, InGroup<AutomaticReferenceCountingABI>,
+  DefaultIgnore;
+def warn_arc_retained_assign : Warning<
+  "cannot assign retained object to %select{weak|unsafe_unretained}0 variable">;
+def warn_arc_trivial_member_function_with_object_member : Warning<
+  "%0 cannot be shared between ARC and non-ARC "
+  "code; add a non-trivial %select{copy constructor|copy assignment operator|"
+  "destructor}1 to make it ABI-compatible">, 
+  InGroup<AutomaticReferenceCountingABI>, DefaultIgnore;
+def err_arc_new_array_without_lifetime : Error<
+  "'new' cannot allocate an array of %0 with no explicit lifetime">;
+def warn_err_new_delete_object_array : Warning<
+  "%select{allocating|destroying}0 an array of %1; this array must not "
+  "%select{be deleted in|have been allocated from}0 non-ARC code">,
+  InGroup<AutomaticReferenceCountingABI>, DefaultIgnore;
+def err_arc_autoreleasing_var : Error<
+  "%select{__block variables|global variables|fields|ivars}0 cannot have "
+  "__autoreleasing lifetime">;
+def err_arc_thread_lifetime : Error<
+  "thread-local variable has non-trivial lifetime: type is %0">;
+def err_arc_indirect_no_lifetime : Error<
+  "%select{pointer|reference}1 to non-const type %0 with no explicit lifetime">,
+  InGroup<AutomaticReferenceCounting>;
+def err_arc_array_param_no_lifetime : Error<
+  "must explicitly describe intended lifetime of an object array parameter">;
+def err_arc_pseudo_dtor_inconstant_quals : Error<
+  "pseudo-destructor destroys object of type %0 with inconsistently-qualified "
+  "type %1">;
+def err_arc_init_method_unrelated_result_type : Error<
+  "init methods must return a type related to the receiver type">;
+def err_arc_nonlocal_writeback : Error<
+  "passing address of %select{non-local|non-scalar}0 object to "
+  "__autoreleasing parameter for write-back">;
+def err_arc_method_not_found : Error<
+  "no known %select{instance|class}1 method for selector %0">;
+def err_arc_receiver_forward_class : Error<
+  "receiver %0 for class message is a forward declaration">;
+def err_arc_may_not_respond : Error<
+  "receiver type %0 for instance message does not declare a method with "
+  "selector %1">;
+def err_arc_receiver_forward_instance : Error<
+  "receiver type %0 for instance message is a forward declaration">;
+def err_arc_multiple_method_decl : Error< 
+  "multiple methods named %0 found with mismatched result, "
+  "parameter type or attributes">;
+def warn_arc_retain_cycle : Warning<
+  "capturing %0 strongly in this block is likely to lead to a retain cycle">,
+  InGroup<DiagGroup<"retain-cycles">>;
+def note_arc_retain_cycle_owner : Note<
+  "block will be retained by %select{the captured object|an object strongly "
+  "retained by the captured object}0">;
+def note_nontrivial_objc_lifetime : Note<
+  "because type %0 has %select{no|no|__strong|__weak|__autoreleasing}1 "
+  "lifetime">;
+def warn_arc_object_memaccess : Warning<
+  "%select{destination for|source of}0 this %1 call is a pointer to "
+  "lifetime-qualified type %2">, InGroup<DiagGroup<"non-pod-memaccess">>;
+
+def err_arc_strong_property_lifetime : Error<
+  "existing ivar %1 for strong property %0 may not be "
+  "%select{|__unsafe_unretained||__weak}2">;
+def err_arc_assign_property_lifetime : Error<
+  "existing ivar %1 for unsafe_unretained property %0 must be __unsafe_unretained">;
+def err_arc_inconsistent_property_lifetime : Error<
+  "%select{strong|weak|unsafe_unretained}1 property %0 may not also be "
+  "declared %select{|__unsafe_unretained|__strong|__weak|__autoreleasing}2">;
+def err_arc_atomic_lifetime : Error<
+  "cannot perform atomic operation on a pointer to type %0: type has "
+  "non-trivial lifetime">;
+
+def err_arc_bridge_cast_incompatible : Error<
+  "incompatible types casting %0 to %1 with a %select{__bridge|"
+  "__bridge_transfer|__bridge_retained}2 cast">;
+def err_arc_bridge_cast_wrong_kind : Error<
+  "cast of %select{Objective-C|block|C}0 pointer type %1 to "
+  "%select{Objective-C|block|C}2 pointer type %3 cannot use %select{__bridge|"
+  "__bridge_transfer|__bridge_retained}4">;
+def err_arc_cast_requires_bridge : Error<
+  "cast of %select{Objective-C|block|C}0 pointer type %1 to "
+  "%select{Objective-C|block|C}2 pointer type %3 requires a bridged cast">;
+def note_arc_bridge : Note<
+  "use __bridge to convert directly (no change in ownership)">;
+def note_arc_bridge_transfer : Note<
+  "use __bridge_transfer to transfer ownership of a +1 %0 into ARC">;
+def note_arc_bridge_retained : Note<
+  "use __bridge_retained to make an ARC object available as a +1 %0">;
+
+} // ARC category name
+
 def err_flexible_array_init_needs_braces : Error<
   "flexible array requires brace-enclosed initializer">;
 def err_illegal_decl_array_of_functions : Error<
@@ -3337,6 +3510,15 @@
   "|sending %0 to parameter of type %1"
   "|casting %0 to type %1}2"
   " changes address space of pointer">;
+def err_typecheck_incompatible_lifetime : Error<
+  "%select{assigning %1 to %0"
+  "|passing %0 to parameter of type %1"
+  "|returning %0 from a function with result type %1"
+  "|converting %0 to type %1"
+  "|initializing %0 with an expression of type %1"
+  "|sending %0 to parameter of type %1"
+  "|casting %0 to type %1}2"
+  " changes retain/release properties of pointer">;
 def err_typecheck_convert_ambiguous : Error<
   "ambiguity in initializing value of type %0 with initializer of type %1">;
 def err_typecheck_comparison_of_distinct_blocks : Error<

Modified: cfe/trunk/include/clang/Basic/LangOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/LangOptions.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/LangOptions.h (original)
+++ cfe/trunk/include/clang/Basic/LangOptions.h Wed Jun 15 18:02:42 2011
@@ -130,6 +130,10 @@
   unsigned DefaultFPContract : 1; // Default setting for FP_CONTRACT
   // FIXME: This is just a temporary option, for testing purposes.
   unsigned NoBitFieldTypeAlign : 1;
+  unsigned ObjCAutoRefCount : 1; // Objective C automated reference counting
+  unsigned ObjCNoAutoRefCountRuntime : 1; // ARC w/o extra runtime support
+  unsigned ObjCInferRelatedReturnType : 1; // Infer Objective-C related return
+                                           // types
   unsigned FakeAddressSpaceMap : 1; // Use a fake address space map, for
                                     // testing languages such as OpenCL.
 
@@ -172,6 +176,8 @@
     Trigraphs = BCPLComment = Bool = DollarIdents = AsmPreprocessor = 0;
     GNUMode = GNUKeywords = ImplicitInt = Digraphs = 0;
     HexFloats = 0;
+    ObjCAutoRefCount = ObjCNoAutoRefCountRuntime = 0;
+    ObjCInferRelatedReturnType = 0;
     GC = ObjC1 = ObjC2 = ObjCNonFragileABI = ObjCNonFragileABI2 = 0;
     AppleKext = 0;
     ObjCDefaultSynthProperties = 0;

Modified: cfe/trunk/include/clang/Basic/StmtNodes.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/StmtNodes.td?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/StmtNodes.td (original)
+++ cfe/trunk/include/clang/Basic/StmtNodes.td Wed Jun 15 18:02:42 2011
@@ -37,6 +37,7 @@
 def ObjCAtThrowStmt : Stmt;
 def ObjCAtSynchronizedStmt : Stmt;
 def ObjCForCollectionStmt : Stmt;
+def ObjCAutoreleasePoolStmt : Stmt;
 
 // C++ statments
 def CXXCatchStmt : Stmt;
@@ -130,6 +131,10 @@
 def ObjCIvarRefExpr : DStmt<Expr>;
 def ObjCPropertyRefExpr : DStmt<Expr>;
 def ObjCIsaExpr : DStmt<Expr>;
+def ObjCIndirectCopyRestoreExpr : DStmt<Expr>;
+
+// Obj-C ARC Expressions.
+def ObjCBridgedCastExpr : DStmt<ExplicitCastExpr>;
 
 // CUDA Expressions.
 def CUDAKernelCallExpr : DStmt<CallExpr>;

Modified: cfe/trunk/include/clang/Basic/TokenKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TokenKinds.def?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/TokenKinds.def (original)
+++ cfe/trunk/include/clang/Basic/TokenKinds.def Wed Jun 15 18:02:42 2011
@@ -422,6 +422,11 @@
 KEYWORD(__vector                    , KEYALTIVEC)
 KEYWORD(__pixel                     , KEYALTIVEC)
 
+// Objective-C ARC keywords.
+KEYWORD(__bridge                     , KEYARC)
+KEYWORD(__bridge_transfer            , KEYARC)
+KEYWORD(__bridge_retained            , KEYARC)
+
 // Alternate spelling for various tokens.  There are GCC extensions in all
 // languages, but should not be disabled in strict conformance mode.
 ALIAS("__alignof__"  , __alignof  , KEYALL)
@@ -507,6 +512,7 @@
 OBJC1_AT_KEYWORD(catch)
 OBJC1_AT_KEYWORD(finally)
 OBJC1_AT_KEYWORD(synchronized)
+OBJC1_AT_KEYWORD(autoreleasepool)
 
 OBJC2_AT_KEYWORD(property)
 OBJC2_AT_KEYWORD(package)

Modified: cfe/trunk/include/clang/Driver/CC1Options.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CC1Options.td?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/CC1Options.td (original)
+++ cfe/trunk/include/clang/Driver/CC1Options.td Wed Jun 15 18:02:42 2011
@@ -383,6 +383,13 @@
   HelpText<"Create a module definition file">;
 }
 
+def arcmt_check : Flag<"-arcmt-check">,
+  HelpText<"Check for ARC migration issues that need manual handling">;
+def arcmt_modify : Flag<"-arcmt-modify">,
+  HelpText<"Apply modifications to files to conform to ARC">;
+def arcmt_modify_in_memory : Flag<"-arcmt-modify-in-memory">,
+  HelpText<"Apply ARC conforming modifications & compile using memory buffers">;
+
 def import_module : Separate<"-import-module">,
   HelpText<"Import a module definition file">;
 
@@ -479,6 +486,14 @@
   HelpText<"Specify the class to use for constant Objective-C string objects.">;
 def fno_constant_cfstrings : Flag<"-fno-constant-cfstrings">,
   HelpText<"Enable creation of CodeFoundation-type constant strings">;
+def fobjc_arc : Flag<"-fobjc-arc">,
+  HelpText<"Synthesize retain and release calls for Objective-C pointers">;
+def fobjc_arc_cxxlib_EQ : Joined<"-fobjc-arc-cxxlib=">,
+  HelpText<"Objective-C++ Automatic Reference Counting standard library kind">;
+def fobjc_no_arc_runtime : Flag<"-fobjc-no-arc-runtime">,
+  HelpText<"Implement -fobjc-arc without any extra runtime support">;
+def fobjc_arc_exceptions : Flag<"-fobjc-arc-exceptions">,
+  HelpText<"Use EH-safe code when synthesizing retains and releases in -fobjc-arc">;
 def fobjc_gc : Flag<"-fobjc-gc">,
   HelpText<"Enable Objective-C garbage collection">;
 def fobjc_gc_only : Flag<"-fobjc-gc-only">,

Modified: cfe/trunk/include/clang/Driver/Options.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Options.td?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/Options.td (original)
+++ cfe/trunk/include/clang/Driver/Options.td Wed Jun 15 18:02:42 2011
@@ -112,6 +112,13 @@
 def ccc_print_bindings : Flag<"-ccc-print-bindings">, CCCDebugOpt,
   HelpText<"Show bindings of tools to actions">;
 
+def ccc_arrmt_check : Flag<"-ccc-arrmt-check">, CCCDriverOpt,
+  HelpText<"Check for ARC migration issues that need manual handling">;
+def ccc_arrmt_modify : Flag<"-ccc-arrmt-modify">, CCCDriverOpt,
+  HelpText<"Apply modifications to files to conform to ARC">;
+def ccc_arrmt_modify_in_memory : Flag<"-ccc-arrmt-modify-in-memory">,
+  HelpText<"Apply ARC conforming modifications & compile using memory buffers">;
+
 // Make sure all other -ccc- options are rejected.
 def ccc_ : Joined<"-ccc-">, Group<ccc_Group>, Flags<[Unsupported]>;
 
@@ -382,6 +389,10 @@
 def fno_working_directory : Flag<"-fno-working-directory">, Group<f_Group>;
 def fno_wrapv : Flag<"-fno-wrapv">, Group<f_Group>;
 def fno_zero_initialized_in_bss : Flag<"-fno-zero-initialized-in-bss">, Group<f_Group>;
+def fobjc_arc : Flag<"-fobjc-arc">, Group<f_Group>;
+def fno_objc_arc : Flag<"-fno-objc-arc">, Group<f_Group>;
+def fobjc_arc_exceptions : Flag<"-fobjc-arc-exceptions">, Group<f_Group>;
+def fno_objc_arc_exceptions : Flag<"-fno-objc-arc-exceptions">, Group<f_Group>;
 def fobjc_atdefs : Flag<"-fobjc-atdefs">, Group<clang_ignored_f_Group>;
 def fobjc_call_cxx_cdtors : Flag<"-fobjc-call-cxx-cdtors">, Group<clang_ignored_f_Group>;
 def fobjc_default_synthesize_properties : 
@@ -392,6 +403,10 @@
 def fobjc_gc : Flag<"-fobjc-gc">, Group<f_Group>;
 def fobjc_legacy_dispatch : Flag<"-fobjc-legacy-dispatch">, Group<f_Group>;
 def fobjc_new_property : Flag<"-fobjc-new-property">, Group<clang_ignored_f_Group>;
+def fobjc_infer_related_result_type : Flag<"-fobjc-infer-related-result-type">, 
+                                      Group<f_Group>;
+def fno_objc_infer_related_result_type : Flag<
+  "-fno-objc-infer-related-result-type">, Group<f_Group>;
 
 // Objective-C ABI options.
 def fobjc_abi_version_EQ : Joined<"-fobjc-abi-version=">, Group<f_Group>;

Modified: cfe/trunk/include/clang/Driver/ToolChain.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/ToolChain.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/ToolChain.h (original)
+++ cfe/trunk/include/clang/Driver/ToolChain.h Wed Jun 15 18:02:42 2011
@@ -166,6 +166,9 @@
   /// UseSjLjExceptions - Does this tool chain use SjLj exceptions.
   virtual bool UseSjLjExceptions() const { return false; }
 
+  /// HasARCRuntime - Does this tool chain provide a specialized ARC runtime.
+  virtual bool HasARCRuntime() const { return false; }
+
   /// ComputeLLVMTriple - Return the LLVM target triple to use, after taking
   /// command line arguments into account.
   virtual std::string ComputeLLVMTriple(const ArgList &Args) const;
@@ -184,7 +187,8 @@
   /// AddClangCXXStdlibIncludeArgs - Add the clang -cc1 level arguments to set
   /// the include paths to use for the given C++ standard library type.
   virtual void AddClangCXXStdlibIncludeArgs(const ArgList &Args,
-                                            ArgStringList &CmdArgs) const;
+                                            ArgStringList &CmdArgs,
+                                            bool ObjCXXAutoRefCount) const;
 
   /// AddCXXStdlibLibArgs - Add the system specific linker arguments to use
   /// for the given C++ standard library type.

Modified: cfe/trunk/include/clang/Frontend/CodeGenOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/CodeGenOptions.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/CodeGenOptions.h (original)
+++ cfe/trunk/include/clang/Frontend/CodeGenOptions.h Wed Jun 15 18:02:42 2011
@@ -36,6 +36,7 @@
   };
 
   unsigned AsmVerbose        : 1; /// -dA, -fverbose-asm.
+  unsigned ObjCAutoRefCountExceptions : 1; /// Whether ARC should be EH-safe.
   unsigned CXAAtExit         : 1; /// Use __cxa_atexit for calling destructors.
   unsigned CXXCtorDtorAliases: 1; /// Emit complete ctors/dtors as linker
                                   /// aliases to base ctors when possible.
@@ -133,6 +134,7 @@
 public:
   CodeGenOptions() {
     AsmVerbose = 0;
+    ObjCAutoRefCountExceptions = 0;
     CXAAtExit = 1;
     CXXCtorDtorAliases = 0;
     DataSections = 0;

Modified: cfe/trunk/include/clang/Frontend/FrontendOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendOptions.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/FrontendOptions.h (original)
+++ cfe/trunk/include/clang/Frontend/FrontendOptions.h Wed Jun 15 18:02:42 2011
@@ -77,6 +77,13 @@
   unsigned FixWhatYouCan : 1;              ///< Apply fixes even if there are
                                            /// unfixable errors.
 
+  enum {
+    ARCMT_None,
+    ARCMT_Check,
+    ARCMT_Modify,
+    ARCMT_ModifyInMemory
+  } ARCMTAction;
+
   /// The input files and their types.
   std::vector<std::pair<InputKind, std::string> > Inputs;
 
@@ -131,6 +138,7 @@
     ShowStats = 0;
     ShowTimers = 0;
     ShowVersion = 0;
+    ARCMTAction = ARCMT_None;
   }
 
   /// getInputKindForExtension - Return the appropriate input kind for a file

Modified: cfe/trunk/include/clang/Frontend/PreprocessorOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PreprocessorOptions.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/PreprocessorOptions.h (original)
+++ cfe/trunk/include/clang/Frontend/PreprocessorOptions.h Wed Jun 15 18:02:42 2011
@@ -26,6 +26,15 @@
 class Preprocessor;
 class LangOptions;
 
+/// \brief Enumerate the kinds of standard library that 
+enum ObjCXXARCStandardLibraryKind {
+  ARCXX_nolib,
+  /// \brief libc++
+  ARCXX_libcxx,
+  /// \brief libstdc++
+  ARCXX_libstdcxx
+};
+  
 /// PreprocessorOptions - This class is used for passing the various options
 /// used in preprocessor initialization to InitializePreprocessor().
 class PreprocessorOptions {
@@ -104,6 +113,11 @@
   /// compiler invocation and its buffers will be reused.
   bool RetainRemappedFileBuffers;
   
+  /// \brief The Objective-C++ ARC standard library that we should support,
+  /// by providing appropriate definitions to retrofit the standard library
+  /// with support for lifetime-qualified pointers.
+  ObjCXXARCStandardLibraryKind ObjCXXARCStandardLibrary;
+  
   typedef std::vector<std::pair<std::string, std::string> >::iterator
     remapped_file_iterator;
   typedef std::vector<std::pair<std::string, std::string> >::const_iterator
@@ -145,7 +159,8 @@
                           DumpDeserializedPCHDecls(false),
                           PrecompiledPreambleBytes(0, true),
                           RemappedFilesKeepOriginalName(true),
-                          RetainRemappedFileBuffers(false) { }
+                          RetainRemappedFileBuffers(false),
+                          ObjCXXARCStandardLibrary(ARCXX_nolib) { }
 
   void addMacroDef(llvm::StringRef Name) {
     Macros.push_back(std::make_pair(Name, false));

Modified: cfe/trunk/include/clang/Frontend/Utils.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/Utils.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/Utils.h (original)
+++ cfe/trunk/include/clang/Frontend/Utils.h Wed Jun 15 18:02:42 2011
@@ -19,6 +19,7 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/Support/raw_ostream.h"
+#include "clang/Basic/Diagnostic.h"
 
 namespace llvm {
 class Triple;

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Wed Jun 15 18:02:42 2011
@@ -1375,6 +1375,7 @@
   StmtResult ParseObjCTryStmt(SourceLocation atLoc);
   StmtResult ParseObjCThrowStmt(SourceLocation atLoc);
   StmtResult ParseObjCSynchronizedStmt(SourceLocation atLoc);
+  StmtResult ParseObjCAutoreleasePoolStmt(SourceLocation atLoc);
 
 
   //===--------------------------------------------------------------------===//
@@ -1616,7 +1617,8 @@
 
   TypeResult ParseTypeName(SourceRange *Range = 0,
                            Declarator::TheContext Context
-                             = Declarator::TypeNameContext);
+                             = Declarator::TypeNameContext,
+                           ObjCDeclSpec *objcQuals = 0);
   void ParseBlockId();
 
   void ProhibitAttributes(ParsedAttributesWithRange &attrs) {

Modified: cfe/trunk/include/clang/Rewrite/Rewriter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Rewrite/Rewriter.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Rewrite/Rewriter.h (original)
+++ cfe/trunk/include/clang/Rewrite/Rewriter.h Wed Jun 15 18:02:42 2011
@@ -183,8 +183,11 @@
   /// InsertText - Insert the specified string at the specified location in the
   /// original buffer.  This method returns true (and does nothing) if the input
   /// location was not rewritable, false otherwise.
+  ///
+  /// \param indentNewLines if true new lines in the string are indented
+  /// using the indentation of the source line in position \arg Loc.
   bool InsertText(SourceLocation Loc, llvm::StringRef Str,
-                  bool InsertAfter = true);
+                  bool InsertAfter = true, bool indentNewLines = false);
 
   /// InsertTextAfter - Insert the specified string at the specified location in
   ///  the original buffer.  This method returns true (and does nothing) if

Modified: cfe/trunk/include/clang/Sema/AttributeList.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AttributeList.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/AttributeList.h (original)
+++ cfe/trunk/include/clang/Sema/AttributeList.h Wed Jun 15 18:02:42 2011
@@ -198,6 +198,7 @@
     AT_objc_method_family,
     AT_cf_returns_not_retained, // Clang-specific.
     AT_cf_returns_retained,     // Clang-specific.
+    AT_cf_returns_autoreleased, // Clang-specific.
     AT_ns_returns_not_retained, // Clang-specific.
     AT_ns_returns_retained,     // Clang-specific.
     AT_ns_returns_autoreleased, // Clang-specific.
@@ -205,6 +206,8 @@
     AT_ns_consumed,             // Clang-specific.
     AT_ns_consumes_self,        // Clang-specific.
     AT_objc_gc,
+    AT_objc_lifetime,           // Clang-specific.
+    AT_objc_precise_lifetime,   // Clang-specific.
     AT_opencl_image_access,     // OpenCL-specific.
     AT_opencl_kernel_function,  // OpenCL-specific.
     AT_overloadable,       // Clang-specific.

Modified: cfe/trunk/include/clang/Sema/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Sema/DeclSpec.h Wed Jun 15 18:02:42 2011
@@ -40,6 +40,7 @@
   class NamespaceDecl;
   class NestedNameSpecifier;
   class NestedNameSpecifierLoc;
+  class ObjCDeclSpec;
   class Preprocessor;
   class Declarator;
   struct TemplateIdAnnotation;
@@ -344,6 +345,8 @@
   void SaveWrittenBuiltinSpecs();
   void SaveStorageSpecifierAsWritten();
 
+  ObjCDeclSpec *ObjCQualifiers;
+
   static bool isTypeRep(TST T) {
     return (T == TST_typename || T == TST_typeofType ||
             T == TST_underlyingType);
@@ -383,7 +386,8 @@
       ProtocolQualifiers(0),
       NumProtocolQualifiers(0),
       ProtocolLocs(0),
-      writtenBS() {
+      writtenBS(),
+      ObjCQualifiers(0) {
   }
   ~DeclSpec() {
     delete [] ProtocolQualifiers;
@@ -653,6 +657,9 @@
     return writtenBS;
   }
 
+  ObjCDeclSpec *getObjCQualifiers() const { return ObjCQualifiers; }
+  void setObjCQualifiers(ObjCDeclSpec *quals) { ObjCQualifiers = quals; }
+
   /// isMissingDeclaratorOk - This checks if this DeclSpec can stand alone,
   /// without a Declarator. Only tag declspecs can stand alone.
   bool isMissingDeclaratorOk();
@@ -689,7 +696,10 @@
     DQ_PR_copy = 0x20,
     DQ_PR_nonatomic = 0x40,
     DQ_PR_setter = 0x80,
-    DQ_PR_atomic = 0x100
+    DQ_PR_atomic = 0x100,
+    DQ_PR_weak =   0x200,
+    DQ_PR_strong = 0x400,
+    DQ_PR_unsafe_unretained = 0x800
   };
 
 
@@ -723,7 +733,7 @@
   ObjCDeclQualifier objcDeclQualifier : 6;
 
   // NOTE: VC++ treats enums as signed, avoid using ObjCPropertyAttributeKind
-  unsigned PropertyAttributes : 9;
+  unsigned PropertyAttributes : 12;
   IdentifierInfo *GetterName;    // getter name of NULL if no getter
   IdentifierInfo *SetterName;    // setter name of NULL if no setter
 };

Modified: cfe/trunk/include/clang/Sema/DelayedDiagnostic.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DelayedDiagnostic.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/DelayedDiagnostic.h (original)
+++ cfe/trunk/include/clang/Sema/DelayedDiagnostic.h Wed Jun 15 18:02:42 2011
@@ -112,7 +112,7 @@
 /// the complete parsing of the current declaration.
 class DelayedDiagnostic {
 public:
-  enum DDKind { Deprecation, Access };
+  enum DDKind { Deprecation, Access, ForbiddenType };
 
   unsigned char Kind; // actually a DDKind
   bool Triggered;
@@ -135,6 +135,20 @@
     return DD;
   }
 
+  static DelayedDiagnostic makeForbiddenType(SourceLocation loc,
+                                             unsigned diagnostic,
+                                             QualType type,
+                                             unsigned argument) {
+    DelayedDiagnostic DD;
+    DD.Kind = ForbiddenType;
+    DD.Triggered = false;
+    DD.Loc = loc;
+    DD.ForbiddenTypeData.Diagnostic = diagnostic;
+    DD.ForbiddenTypeData.OperandType = type.getAsOpaquePtr();
+    DD.ForbiddenTypeData.Argument = argument;
+    return DD;
+  }
+
   AccessedEntity &getAccessData() {
     assert(Kind == Access && "Not an access diagnostic.");
     return *reinterpret_cast<AccessedEntity*>(AccessData);
@@ -155,6 +169,25 @@
                            DeprecationData.MessageLen);
   }
 
+  /// The diagnostic ID to emit.  Used like so:
+  ///   Diag(diag.Loc, diag.getForbiddenTypeDiagnostic())
+  ///     << diag.getForbiddenTypeOperand()
+  ///     << diag.getForbiddenTypeArgument();
+  unsigned getForbiddenTypeDiagnostic() const {
+    assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
+    return ForbiddenTypeData.Diagnostic;
+  }
+
+  unsigned getForbiddenTypeArgument() const {
+    assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
+    return ForbiddenTypeData.Argument;
+  }
+
+  QualType getForbiddenTypeOperand() const {
+    assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
+    return QualType::getFromOpaquePtr(ForbiddenTypeData.OperandType);
+  }
+
 private:
   union {
     /// Deprecation.
@@ -164,6 +197,12 @@
       size_t MessageLen;
     } DeprecationData;
 
+    struct {
+      unsigned Diagnostic;
+      unsigned Argument;
+      void *OperandType;
+    } ForbiddenTypeData;
+
     /// Access control.
     char AccessData[sizeof(AccessedEntity)];
   };

Modified: cfe/trunk/include/clang/Sema/Initialization.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Initialization.h (original)
+++ cfe/trunk/include/clang/Sema/Initialization.h Wed Jun 15 18:02:42 2011
@@ -86,9 +86,13 @@
   QualType Type;
   
   union {
-    /// \brief When Kind == EK_Variable, EK_Parameter, or EK_Member, 
-    /// the VarDecl, ParmVarDecl, or FieldDecl, respectively.
+    /// \brief When Kind == EK_Variable or EK_Member, the VarDecl or
+    /// FieldDecl, respectively.
     DeclaratorDecl *VariableOrMember;
+
+    /// \brief When Kind == EK_Parameter, the ParmVarDecl, with the
+    /// low bit indicating whether the parameter is "consumed".
+    uintptr_t Parameter;
     
     /// \brief When Kind == EK_Temporary, the type source information for
     /// the temporary.
@@ -123,11 +127,6 @@
     : Kind(EK_Variable), Parent(0), Type(Var->getType()),
       VariableOrMember(Var) { }
   
-  /// \brief Create the initialization entity for a parameter.
-  InitializedEntity(ParmVarDecl *Parm)
-    : Kind(EK_Parameter), Parent(0), Type(Parm->getType().getUnqualifiedType()),
-      VariableOrMember(Parm) { }
-  
   /// \brief Create the initialization entity for the result of a
   /// function, throwing an object, performing an explicit cast, or
   /// initializing a parameter for which there is no declaration.
@@ -157,20 +156,28 @@
   /// \brief Create the initialization entity for a parameter.
   static InitializedEntity InitializeParameter(ASTContext &Context,
                                                ParmVarDecl *Parm) {
-    InitializedEntity Res(Parm);
-    Res.Type = Context.getVariableArrayDecayedType(Res.Type);
-    return Res;
+    bool Consumed = (Context.getLangOptions().ObjCAutoRefCount &&
+                     Parm->hasAttr<NSConsumedAttr>());
+
+    InitializedEntity Entity;
+    Entity.Kind = EK_Parameter;
+    Entity.Type = Context.getVariableArrayDecayedType(
+                                       Parm->getType().getUnqualifiedType());
+    Entity.Parent = 0;
+    Entity.Parameter = (Consumed | reinterpret_cast<uintptr_t>(Parm));
+    return Entity;
   }
 
   /// \brief Create the initialization entity for a parameter that is
   /// only known by its type.
   static InitializedEntity InitializeParameter(ASTContext &Context,
-                                               QualType Type) {
+                                               QualType Type,
+                                               bool Consumed) {
     InitializedEntity Entity;
     Entity.Kind = EK_Parameter;
     Entity.Type = Context.getVariableArrayDecayedType(Type);
     Entity.Parent = 0;
-    Entity.VariableOrMember = 0;
+    Entity.Parameter = (Consumed);
     return Entity;
   }
 
@@ -268,6 +275,13 @@
   /// \brief Determine whether this initialization allows the named return 
   /// value optimization, which also applies to thrown objects.
   bool allowsNRVO() const;
+
+  /// \brief Determine whether this initialization consumes the
+  /// parameter.
+  bool isParameterConsumed() const {
+    assert(getKind() == EK_Parameter && "Not a parameter");
+    return (Parameter & 1);
+  }
                                   
   /// \brief Retrieve the base specifier.
   CXXBaseSpecifier *getBaseSpecifier() const {
@@ -287,7 +301,7 @@
     assert(getKind() == EK_Result && "No 'return' location!");
     return SourceLocation::getFromRawEncoding(LocAndNRVO.Location);
   }
-  
+
   /// \brief Determine the location of the 'throw' keyword when initializing
   /// an exception object.
   SourceLocation getThrowLoc() const {
@@ -325,8 +339,10 @@
     SIK_Value = IK_Value,     ///< Value initialization
     SIK_ImplicitValue,        ///< Implicit value initialization
     SIK_DirectCast,  ///< Direct initialization due to a cast
-    /// \brief Direct initialization due to a C-style or functional cast.
-    SIK_DirectCStyleOrFunctionalCast
+    /// \brief Direct initialization due to a C-style cast.
+    SIK_DirectCStyleCast,
+    /// \brief Direct initialization due to a functional-style cast.
+    SIK_DirectFunctionalCast
   };
   
   /// \brief The kind of initialization being performed.
@@ -352,15 +368,29 @@
     return InitializationKind(SIK_Direct, InitLoc, LParenLoc, RParenLoc);
   }
 
-  /// \brief Create a direct initialization due to a cast.
-  static InitializationKind CreateCast(SourceRange TypeRange,
-                                       bool IsCStyleCast) {
-    return InitializationKind(IsCStyleCast? SIK_DirectCStyleOrFunctionalCast
-                                          : SIK_DirectCast,
+  /// \brief Create a direct initialization due to a cast that isn't a C-style 
+  /// or functional cast.
+  static InitializationKind CreateCast(SourceRange TypeRange) {
+    return InitializationKind(SIK_DirectCast,
                               TypeRange.getBegin(), TypeRange.getBegin(), 
                               TypeRange.getEnd());
   }
   
+  /// \brief Create a direct initialization for a C-style cast.
+  static InitializationKind CreateCStyleCast(SourceLocation StartLoc,
+                                             SourceRange TypeRange) {
+    return InitializationKind(SIK_DirectCStyleCast,
+                              StartLoc, TypeRange.getBegin(), 
+                              TypeRange.getEnd());
+  }
+
+  /// \brief Create a direct initialization for a functional cast.
+  static InitializationKind CreateFunctionalCast(SourceRange TypeRange) {
+    return InitializationKind(SIK_DirectFunctionalCast,
+                              TypeRange.getBegin(), TypeRange.getBegin(), 
+                              TypeRange.getEnd());
+  }
+
   /// \brief Create a copy initialization.
   static InitializationKind CreateCopy(SourceLocation InitLoc,
                                        SourceLocation EqualLoc) {
@@ -393,12 +423,24 @@
   
   /// \brief Determine whether this initialization is an explicit cast.
   bool isExplicitCast() const {
-    return Kind == SIK_DirectCast || Kind == SIK_DirectCStyleOrFunctionalCast;
+    return Kind == SIK_DirectCast || 
+           Kind == SIK_DirectCStyleCast ||
+           Kind == SIK_DirectFunctionalCast;
   }
   
   /// \brief Determine whether this initialization is a C-style cast.
   bool isCStyleOrFunctionalCast() const { 
-    return Kind == SIK_DirectCStyleOrFunctionalCast; 
+    return Kind == SIK_DirectCStyleCast || Kind == SIK_DirectFunctionalCast; 
+  }
+
+  /// brief Determine whether this is a C-style cast.
+  bool isCStyleCast() const {
+    return Kind == SIK_DirectCStyleCast;
+  }
+
+  /// brief Determine whether this is a functional-style cast.
+  bool isFunctionalCast() const {
+    return Kind == SIK_DirectFunctionalCast;
   }
 
   /// \brief Determine whether this initialization is an implicit
@@ -500,7 +542,13 @@
     SK_ObjCObjectConversion,
     /// \brief Array initialization (from an array rvalue).
     /// This is a GNU C extension.
-    SK_ArrayInit
+    SK_ArrayInit,
+    /// \brief Pass an object by indirect copy-and-restore.
+    SK_PassByIndirectCopyRestore,
+    /// \brief Pass an object by indirect restore.
+    SK_PassByIndirectRestore,
+    /// \brief Produce an Objective-C object pointer.
+    SK_ProduceObjCObject
   };
   
   /// \brief A single step in the initialization sequence.
@@ -774,6 +822,13 @@
   /// \brief Add an array initialization step.
   void AddArrayInitStep(QualType T);
 
+  /// \brief Add a step to pass an object by indirect copy-restore.
+  void AddPassByIndirectCopyRestoreStep(QualType T, bool shouldCopy);
+
+  /// \brief Add a step to "produce" an Objective-C object (by
+  /// retaining it).
+  void AddProduceObjCObjectStep(QualType T);
+
   /// \brief Note that this initialization sequence failed.
   void SetFailed(FailureKind Failure) {
     SequenceKind = FailedSequence;

Modified: cfe/trunk/include/clang/Sema/Overload.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Overload.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Overload.h (original)
+++ cfe/trunk/include/clang/Sema/Overload.h Wed Jun 15 18:02:42 2011
@@ -77,6 +77,7 @@
     ICK_Complex_Real,          ///< Complex-real conversions (C99 6.3.1.7)
     ICK_Block_Pointer_Conversion,    ///< Block Pointer conversions 
     ICK_TransparentUnionConversion, /// Transparent Union Conversions
+    ICK_Writeback_Conversion,  ///< Objective-C ARC writeback conversion
     ICK_Num_Conversion_Kinds   ///< The number of conversion kinds
   };
 
@@ -100,10 +101,11 @@
   /// 13.3.3.1.1) and are listed such that better conversion ranks
   /// have smaller values.
   enum ImplicitConversionRank {
-    ICR_Exact_Match = 0,        ///< Exact Match
-    ICR_Promotion,              ///< Promotion
-    ICR_Conversion,             ///< Conversion
-    ICR_Complex_Real_Conversion ///< Complex <-> Real conversion
+    ICR_Exact_Match = 0,         ///< Exact Match
+    ICR_Promotion,               ///< Promotion
+    ICR_Conversion,              ///< Conversion
+    ICR_Complex_Real_Conversion, ///< Complex <-> Real conversion
+    ICR_Writeback_Conversion     ///< ObjC ARC writeback conversion
   };
 
   ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind);
@@ -137,6 +139,10 @@
     /// (C++ 4.2p2).
     unsigned DeprecatedStringLiteralToCharPtr : 1;
 
+    /// \brief Whether the qualification conversion involves a change in the
+    /// Objective-C lifetime (for automatic reference counting).
+    unsigned QualificationIncludesObjCLifetime : 1;
+    
     /// IncompatibleObjC - Whether this is an Objective-C conversion
     /// that we should warn about (if we actually use it).
     unsigned IncompatibleObjC : 1;
@@ -163,6 +169,10 @@
     /// non-static member function without a ref-qualifier.
     unsigned BindsImplicitObjectArgumentWithoutRefQualifier : 1;
     
+    /// \brief Whether this binds a reference to an object with a different
+    /// Objective-C lifetime qualifier.
+    unsigned ObjCLifetimeConversionBinding : 1;
+    
     /// FromType - The type that this conversion is converting
     /// from. This is an opaque pointer that can be translated into a
     /// QualType.

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Jun 15 18:02:42 2011
@@ -108,6 +108,7 @@
   class ObjCInterfaceDecl;
   class ObjCIvarDecl;
   template <class T> class ObjCList;
+  class ObjCMessageExpr;
   class ObjCMethodDecl;
   class ObjCPropertyDecl;
   class ObjCProtocolDecl;
@@ -247,6 +248,10 @@
   /// VisContext - Manages the stack for #pragma GCC visibility.
   void *VisContext; // Really a "PragmaVisStack*"
 
+  /// ExprNeedsCleanups - True if the current evaluation context
+  /// requires cleanups to be run at its conclusion.
+  bool ExprNeedsCleanups;
+
   /// \brief Stack containing information about each of the nested
   /// function, block, and method scopes that are currently active.
   ///
@@ -555,6 +560,9 @@
     /// \brief The expression evaluation context.
     ExpressionEvaluationContext Context;
 
+    /// \brief Whether the enclosing context needed a cleanup.
+    bool ParentNeedsCleanups;
+
     /// \brief The number of temporaries that were active when we
     /// entered this expression evaluation context.
     unsigned NumTemporaries;
@@ -573,8 +581,10 @@
     PotentiallyEmittedDiagnostics *PotentiallyDiagnosed;
 
     ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context,
-                                      unsigned NumTemporaries)
-      : Context(Context), NumTemporaries(NumTemporaries),
+                                      unsigned NumTemporaries,
+                                      bool ParentNeedsCleanups)
+      : Context(Context), ParentNeedsCleanups(ParentNeedsCleanups),
+        NumTemporaries(NumTemporaries),
         PotentiallyReferenced(0), PotentiallyDiagnosed(0) { }
 
     void addReferencedDecl(SourceLocation Loc, Decl *Decl) {
@@ -766,7 +776,7 @@
     return FunctionScopes.back();
   }
 
-  bool hasAnyErrorsInThisFunction() const;
+  bool hasAnyUnrecoverableErrorsInThisFunction() const;
 
   /// \brief Retrieve the current block, if any.
   sema::BlockScopeInfo *getCurBlock();
@@ -838,7 +848,7 @@
       const FunctionProtoType *Source, SourceLocation SourceLoc);
 
   TypeResult ActOnTypeName(Scope *S, Declarator &D);
-
+  
   bool RequireCompleteType(SourceLocation Loc, QualType T,
                            const PartialDiagnostic &PD,
                            std::pair<SourceLocation, PartialDiagnostic> Note);
@@ -1305,13 +1315,13 @@
                              bool IsForUsingDecl);
   bool IsOverload(FunctionDecl *New, FunctionDecl *Old, bool IsForUsingDecl);
 
-  bool TryImplicitConversion(InitializationSequence &Sequence,
-                             const InitializedEntity &Entity,
-                             Expr *From,
-                             bool SuppressUserConversions,
-                             bool AllowExplicit,
-                             bool InOverloadResolution,
-                             bool CStyle);
+  ImplicitConversionSequence
+  TryImplicitConversion(Expr *From, QualType ToType,
+                        bool SuppressUserConversions,
+                        bool AllowExplicit,
+                        bool InOverloadResolution,
+                        bool CStyle,
+                        bool AllowObjCWritebackConversion);
 
   bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType);
   bool IsFloatingPointPromotion(QualType FromType, QualType ToType);
@@ -1321,6 +1331,8 @@
                            QualType& ConvertedType, bool &IncompatibleObjC);
   bool isObjCPointerConversion(QualType FromType, QualType ToType,
                                QualType& ConvertedType, bool &IncompatibleObjC);
+  bool isObjCWritebackConversion(QualType FromType, QualType ToType,
+                                 QualType &ConvertedType);
   bool IsBlockPointerConversion(QualType FromType, QualType ToType,
                                 QualType& ConvertedType);
   bool FunctionArgTypesAreEqual(const FunctionProtoType *OldType, 
@@ -1338,7 +1350,7 @@
                                     CXXCastPath &BasePath,
                                     bool IgnoreBaseAccess);
   bool IsQualificationConversion(QualType FromType, QualType ToType,
-                                 bool CStyle);
+                                 bool CStyle, bool &ObjCLifetimeConversion);
   bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType);
 
 
@@ -1853,14 +1865,20 @@
   void AtomicPropertySetterGetterRules(ObjCImplDecl* IMPDecl,
                                        ObjCContainerDecl* IDecl);
 
+  void DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D);
+
   void DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, ObjCInterfaceDecl *SID);
 
+  enum MethodMatchStrategy {
+    MMS_loose,
+    MMS_strict
+  };
+
   /// MatchTwoMethodDeclarations - Checks if two methods' type match and returns
   /// true, or false, accordingly.
   bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method,
                                   const ObjCMethodDecl *PrevMethod,
-                                  bool matchBasedOnSizeAndAlignment = false,
-                                  bool matchBasedOnStrictEqulity = false);
+                                  MethodMatchStrategy strategy = MMS_strict);
 
   /// MatchAllMethodDeclarations - Check methods declaraed in interface or
   /// or protocol against those declared in their implementations.
@@ -2073,10 +2091,13 @@
                                          Expr *SynchExpr,
                                          Stmt *SynchBody);
 
+  StmtResult ActOnObjCAutoreleasePoolStmt(SourceLocation AtLoc, Stmt *Body);
+
   VarDecl *BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo,
                                      SourceLocation StartLoc,
                                      SourceLocation IdLoc,
                                      IdentifierInfo *Id);
+
   Decl *ActOnExceptionDeclarator(Scope *S, Declarator &D);
 
   StmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc,
@@ -2130,6 +2151,9 @@
 
   void HandleDelayedDeprecationCheck(sema::DelayedDiagnostic &DD, Decl *Ctx);
 
+  bool makeUnavailableInSystemHeader(SourceLocation loc,
+                                     llvm::StringRef message);
+
   //===--------------------------------------------------------------------===//
   // Expression Parsing Callbacks: SemaExpr.cpp.
 
@@ -2146,6 +2170,8 @@
 
   void PopExpressionEvaluationContext();
 
+  void DiscardCleanupsInEvaluationContext();
+
   void MarkDeclarationReferenced(SourceLocation Loc, Decl *D);
   void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T);
   void MarkDeclarationsReferencedInExpr(Expr *E);
@@ -4982,6 +5008,15 @@
                               IdentifierInfo *PropertyIvar,
                               SourceLocation PropertyIvarLoc);
 
+  enum ObjCSpecialMethodKind {
+    OSMK_None,
+    OSMK_Alloc,
+    OSMK_New,
+    OSMK_Copy,
+    OSMK_RetainingInit,
+    OSMK_NonRetainingInit
+  };
+
   struct ObjCArgInfo {
     IdentifierInfo *Name;
     SourceLocation NameLoc;
@@ -5020,6 +5055,8 @@
                                               const ObjCObjectPointerType *OPT,
                                               bool IsInstance);
 
+  bool inferObjCARCLifetime(ValueDecl *decl);
+    
   ExprResult
   HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
                             Expr *BaseExpr,
@@ -5098,6 +5135,22 @@
                                   SourceLocation RBracLoc,
                                   MultiExprArg Args);
 
+  ExprResult BuildObjCBridgedCast(SourceLocation LParenLoc,
+                                  ObjCBridgeCastKind Kind,
+                                  SourceLocation BridgeKeywordLoc,
+                                  TypeSourceInfo *TSInfo,
+                                  Expr *SubExpr);
+  
+  ExprResult ActOnObjCBridgedCast(Scope *S,
+                                  SourceLocation LParenLoc,
+                                  ObjCBridgeCastKind Kind,
+                                  SourceLocation BridgeKeywordLoc,
+                                  ParsedType Type,
+                                  SourceLocation RParenLoc,
+                                  Expr *SubExpr);
+  
+  bool checkInitMethod(ObjCMethodDecl *method, QualType receiverTypeIfCall);
+  
   /// \brief Check whether the given new method is a valid override of the
   /// given overridden method, and set any properties that should be inherited.
   ///
@@ -5105,7 +5158,7 @@
   bool CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, 
                                const ObjCMethodDecl *Overridden,
                                bool IsImplementation);
-    
+
   /// \brief Check whether the given method overrides any methods in its class,
   /// calling \c CheckObjCMethodOverride for each overridden method.
   bool CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod, DeclContext *DC);
@@ -5208,12 +5261,26 @@
   /// from the inner expression.
   ExprValueKind CastCategory(Expr *E);
 
+  /// \brief The kind of conversion being performed.
+  enum CheckedConversionKind {
+    /// \brief An implicit conversion.
+    CCK_ImplicitConversion,
+    /// \brief A C-style cast.
+    CCK_CStyleCast,
+    /// \brief A functional-style cast.
+    CCK_FunctionalCast,
+    /// \brief A cast other than a C-style cast.
+    CCK_OtherCast
+  };
+
   /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit
   /// cast.  If there is already an implicit cast, merge into the existing one.
   /// If isLvalue, the result of the cast is an lvalue.
   ExprResult ImpCastExprToType(Expr *E, QualType Type, CastKind CK,
                                ExprValueKind VK = VK_RValue,
-                               const CXXCastPath *BasePath = 0);
+                               const CXXCastPath *BasePath = 0,
+                               CheckedConversionKind CCK 
+                                  = CCK_ImplicitConversion);
 
   /// ScalarTypeToBooleanCastKind - Returns the cast kind corresponding
   /// to the conversion from scalar type ScalarTy to the Boolean type.
@@ -5393,11 +5460,12 @@
   ExprResult PerformImplicitConversion(Expr *From, QualType ToType,
                                        const ImplicitConversionSequence& ICS,
                                        AssignmentAction Action,
-                                       bool CStyle = false);
+                                       CheckedConversionKind CCK
+                                          = CCK_ImplicitConversion);
   ExprResult PerformImplicitConversion(Expr *From, QualType ToType,
                                        const StandardConversionSequence& SCS,
                                        AssignmentAction Action,
-                                       bool CStyle);
+                                       CheckedConversionKind CCK);
 
   /// the following "Check" methods will return a valid/converted QualType
   /// or a null QualType (indicating an error diagnostic was issued).
@@ -5494,12 +5562,14 @@
   ReferenceCompareResult CompareReferenceRelationship(SourceLocation Loc,
                                                       QualType T1, QualType T2,
                                                       bool &DerivedToBase,
-                                                      bool &ObjCConversion);
+                                                      bool &ObjCConversion,
+                                                bool &ObjCLifetimeConversion);
 
   /// CheckCastTypes - Check type constraints for casting between types under
   /// C semantics, or forward to CXXCheckCStyleCast in C++.
-  ExprResult CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *CastExpr,
-                            CastKind &Kind, ExprValueKind &VK, CXXCastPath &BasePath,
+  ExprResult CheckCastTypes(SourceLocation CastStartLoc, SourceRange TyRange, 
+                            QualType CastTy, Expr *CastExpr, CastKind &Kind, 
+                            ExprValueKind &VK, CXXCastPath &BasePath,
                             bool FunctionalStyle = false);
 
   ExprResult checkUnknownAnyCast(SourceRange TyRange, QualType castType,
@@ -5526,6 +5596,20 @@
   ExprResult CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
                                 Expr *CastExpr, CastKind &Kind,
                                 CXXCastPath &BasePath, bool FunctionalStyle);
+  
+  /// \brief Checks for invalid conversions and casts between
+  /// retainable pointers and other pointer kinds.
+  void CheckObjCARCConversion(SourceRange castRange, QualType castType, 
+                              Expr *op, CheckedConversionKind CCK);
+
+  /// checkRetainCycles - Check whether an Objective-C message send
+  /// might create an obvious retain cycle.
+  void checkRetainCycles(ObjCMessageExpr *msg);
+  void checkRetainCycles(Expr *receiver, Expr *argument);
+
+  /// checkWeakUnsafeAssigns - Check whether +1 expr is being assigned
+  /// to weak/__unsafe_unretained.
+  void checkUnsafeAssigns(SourceLocation Loc, QualType LHS, Expr *RHS);
 
   /// CheckMessageArgumentTypes - Check types in an Obj-C message send.
   /// \param Method - May be null.
@@ -5544,7 +5628,7 @@
   QualType getMessageSendResultType(QualType ReceiverType,
                                     ObjCMethodDecl *Method,
                                     bool isClassMessage, bool isSuperMessage);
-    
+
   /// \brief If the given expression involves a message send to a method
   /// with a related result type, emit a note describing what happened.
   void EmitRelatedResultTypeNote(const Expr *E);

Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Wed Jun 15 18:02:42 2011
@@ -922,6 +922,8 @@
       EXPR_OBJC_MESSAGE_EXPR,
       /// \brief An ObjCIsa Expr record.
       EXPR_OBJC_ISA,
+      /// \breif An ObjCIndirectCopyRestoreExpr record.
+      EXPR_OBJC_INDIRECT_COPY_RESTORE,
 
       /// \brief An ObjCForCollectionStmt record.
       STMT_OBJC_FOR_COLLECTION,
@@ -935,6 +937,8 @@
       STMT_OBJC_AT_SYNCHRONIZED,
       /// \brief An ObjCAtThrowStmt record.
       STMT_OBJC_AT_THROW,
+      /// \brief An ObjCAutoreleasePoolStmt record.
+      STMT_OBJC_AUTORELEASE_POOL,
 
       // C++
       
@@ -1002,11 +1006,13 @@
       EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK,// SubstNonTypeTemplateParmPackExpr
 
       // CUDA
+      EXPR_CUDA_KERNEL_CALL,       // CUDAKernelCallExpr      
 
-      EXPR_CUDA_KERNEL_CALL,       // CUDAKernelCallExpr
-      
       // OpenCL
-      EXPR_ASTYPE // An AsTypeExpr record.
+      EXPR_ASTYPE,                 // AsTypeExpr
+      
+      // ARC
+      EXPR_OBJC_BRIDGED_CAST       // ObjCBridgedCastExpr
     };
 
     /// \brief The kinds of designators that can occur in a

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Wed Jun 15 18:02:42 2011
@@ -221,9 +221,9 @@
   DependentTemplateSpecializationTypes(this_()),
   GlobalNestedNameSpecifier(0), IsInt128Installed(false),
   CFConstantStringTypeDecl(0), NSConstantStringTypeDecl(0),
-  ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), jmp_bufDecl(0),
-  sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0),
-  cudaConfigureCallDecl(0),
+  ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), 
+  jmp_bufDecl(0), sigjmp_bufDecl(0), BlockDescriptorType(0), 
+  BlockDescriptorExtendedType(0), cudaConfigureCallDecl(0),
   NullTypeSourceInfo(QualType()),
   SourceMgr(SM), LangOpts(LOpts), ABI(createCXXABI(t)),
   AddrSpaceMap(getAddressSpaceMap(t, LOpts)), Target(t),
@@ -2040,10 +2040,13 @@
     assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
   }
 
-  // FunctionProtoType objects are allocated with extra bytes after them
-  // for two variable size arrays (for parameter and exception types) at the
-  // end of them. Instead of the exception types, there could be a noexcept
-  // expression and a context pointer.
+  // FunctionProtoType objects are allocated with extra bytes after
+  // them for three variable size arrays at the end:
+  //  - parameter types
+  //  - exception types
+  //  - consumed-arguments flags
+  // Instead of the exception types, there could be a noexcept
+  // expression.
   size_t Size = sizeof(FunctionProtoType) +
                 NumArgs * sizeof(QualType);
   if (EPI.ExceptionSpecType == EST_Dynamic)
@@ -2051,6 +2054,9 @@
   else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
     Size += sizeof(Expr*);
   }
+  if (EPI.ConsumedArguments)
+    Size += NumArgs * sizeof(bool);
+
   FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment);
   FunctionProtoType::ExtProtoInfo newEPI = EPI;
   newEPI.ExtInfo = EPI.ExtInfo.withCallingConv(CallConv);
@@ -2925,7 +2931,6 @@
   return CanQualType::CreateUnsafe(Result);
 }
 
-
 QualType ASTContext::getUnqualifiedArrayType(QualType type,
                                              Qualifiers &quals) {
   SplitQualType splitType = type.getSplitUnqualifiedType();
@@ -3725,11 +3730,7 @@
 }
 
 bool ASTContext::BlockRequiresCopying(QualType Ty) const {
-  if (Ty->isBlockPointerType())
-    return true;
-  if (isObjCNSObjectType(Ty))
-    return true;
-  if (Ty->isObjCObjectPointerType())
+  if (Ty->isObjCRetainableType())
     return true;
   if (getLangOptions().CPlusPlus) {
     if (const RecordType *RT = Ty->getAs<RecordType>()) {
@@ -4826,20 +4827,6 @@
 //                        Type Predicates.
 //===----------------------------------------------------------------------===//
 
-/// isObjCNSObjectType - Return true if this is an NSObject object using
-/// NSObject attribute on a c-style pointer type.
-/// FIXME - Make it work directly on types.
-/// FIXME: Move to Type.
-///
-bool ASTContext::isObjCNSObjectType(QualType Ty) const {
-  if (const TypedefType *TDT = dyn_cast<TypedefType>(Ty)) {
-    if (TypedefNameDecl *TD = TDT->getDecl())
-      if (TD->getAttr<ObjCNSObjectAttr>())
-        return true;
-  }
-  return false;
-}
-
 /// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's
 /// garbage collection attribute.
 ///
@@ -5452,6 +5439,9 @@
   if (lbaseInfo.getRegParm() != rbaseInfo.getRegParm())
     return QualType();
 
+  if (lbaseInfo.getProducesResult() != rbaseInfo.getProducesResult())
+    return QualType();
+
   // It's noreturn if either type is.
   // FIXME: some uses, e.g. conditional exprs, really want this to be 'both'.
   bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn();
@@ -5460,10 +5450,7 @@
   if (NoReturn != rbaseInfo.getNoReturn())
     allRTypes = false;
 
-  FunctionType::ExtInfo einfo(NoReturn,
-                              lbaseInfo.getHasRegParm(),
-                              lbaseInfo.getRegParm(),
-                              lbaseInfo.getCC());
+  FunctionType::ExtInfo einfo = lbaseInfo.withNoReturn(NoReturn);
 
   if (lproto && rproto) { // two C99 style function prototypes
     assert(!lproto->hasExceptionSpec() && !rproto->hasExceptionSpec() &&
@@ -5584,7 +5571,8 @@
     // If any of these qualifiers are different, we have a type
     // mismatch.
     if (LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers() ||
-        LQuals.getAddressSpace() != RQuals.getAddressSpace())
+        LQuals.getAddressSpace() != RQuals.getAddressSpace() ||
+        LQuals.getObjCLifetime() != RQuals.getObjCLifetime())
       return QualType();
 
     // Exactly one GC qualifier difference is allowed: __strong is

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Wed Jun 15 18:02:42 2011
@@ -228,6 +228,11 @@
     if (!BaseClassDecl->hasTrivialDestructor())
       data().HasTrivialDestructor = false;
     
+    // A class has an Objective-C object member if... or any of its bases
+    // has an Objective-C object member.
+    if (BaseClassDecl->hasObjectMember())
+      setHasObjectMember(true);
+
     // Keep track of the presence of mutable fields.
     if (BaseClassDecl->hasMutableFields())
       data().HasMutableFields = true;
@@ -698,10 +703,23 @@
     //   A POD struct is a class that is both a trivial class and a 
     //   standard-layout class, and has no non-static data members of type 
     //   non-POD struct, non-POD union (or array of such types).
+    //
+    // Automatic Reference Counting: the presence of a member of Objective-C pointer type
+    // that does not explicitly have no lifetime makes the class a non-POD.
+    // However, we delay setting PlainOldData to false in this case so that
+    // Sema has a chance to diagnostic causes where the same class will be
+    // non-POD with Automatic Reference Counting but a POD without Instant Objects.
+    // In this case, the class will become a non-POD class when we complete
+    // the definition.
     ASTContext &Context = getASTContext();
     QualType T = Context.getBaseElementType(Field->getType());
-    if (!T->isPODType())
+    if (T->isObjCRetainableType() || T.isObjCGCStrong()) {
+      if (!Context.getLangOptions().ObjCAutoRefCount ||
+          T.getObjCLifetime() != Qualifiers::OCL_ExplicitNone)
+        setHasObjectMember(true);
+    } else if (!T.isPODType(Context))
       data().PlainOldData = false;
+    
     if (T->isReferenceType()) {
       data().HasTrivialDefaultConstructor = false;
 
@@ -768,6 +786,8 @@
 
         if (!FieldRec->hasTrivialDestructor())
           data().HasTrivialDestructor = false;
+        if (FieldRec->hasObjectMember())
+          setHasObjectMember(true);
 
         // C++0x [class]p7:
         //   A standard-layout class is a class that:
@@ -1078,6 +1098,20 @@
 void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {
   RecordDecl::completeDefinition();
   
+  if (hasObjectMember() && getASTContext().getLangOptions().ObjCAutoRefCount) {
+    // 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.
+    struct DefinitionData &Data = data();
+    Data.PlainOldData = false;
+    Data.HasTrivialDefaultConstructor = false;
+    Data.HasTrivialCopyConstructor = false;
+    Data.HasTrivialCopyAssignment = false;
+    Data.HasTrivialDestructor = false;
+  }
+  
   // If the class may be abstract (but hasn't been marked as such), check for
   // any pure final overriders.
   if (mayBeAbstract()) {

Modified: cfe/trunk/lib/AST/DeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclObjC.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclObjC.cpp (original)
+++ cfe/trunk/lib/AST/DeclObjC.cpp Wed Jun 15 18:02:42 2011
@@ -474,8 +474,28 @@
   } else // we have a factory method.
     selfTy = Context.getObjCClassType();
 
-  setSelfDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(),
-                                        &Context.Idents.get("self"), selfTy));
+  bool selfIsConsumed = false;
+  if (isInstanceMethod() && Context.getLangOptions().ObjCAutoRefCount) {
+    selfIsConsumed = hasAttr<NSConsumesSelfAttr>();
+
+    // 'self' is always __strong, although as a special case we don't
+    // actually retain it except in init methods.
+    Qualifiers qs;
+    qs.setObjCLifetime(Qualifiers::OCL_Strong);
+    selfTy = Context.getQualifiedType(selfTy, qs);
+
+    // In addition, 'self' is const unless this is an init method.
+    if (getMethodFamily() != OMF_init)
+      selfTy = selfTy.withConst();
+  }
+
+  ImplicitParamDecl *self
+    = ImplicitParamDecl::Create(Context, this, SourceLocation(),
+                                &Context.Idents.get("self"), selfTy);
+  setSelfDecl(self);
+
+  if (selfIsConsumed)
+    self->addAttr(new (Context) NSConsumedAttr(SourceLocation(), Context));
 
   setCmdDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(),
                                        &Context.Idents.get("_cmd"),

Modified: cfe/trunk/lib/AST/DeclPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclPrinter.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclPrinter.cpp (original)
+++ cfe/trunk/lib/AST/DeclPrinter.cpp Wed Jun 15 18:02:42 2011
@@ -933,6 +933,11 @@
     first = false;
   }
 
+  if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_strong) {
+    Out << (first ? ' ' : ',') << "strong";
+    first = false;
+  }
+
   if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_copy) {
     Out << (first ? ' ' : ',') << "copy";
     first = false;

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Wed Jun 15 18:02:42 2011
@@ -1045,6 +1045,10 @@
     return "IntegralComplexCast";
   case CK_IntegralComplexToFloatingComplex:
     return "IntegralComplexToFloatingComplex";
+  case CK_ObjCConsumeObject:
+    return "ObjCConsumeObject";
+  case CK_ObjCProduceObject:
+    return "ObjCProduceObject";
   }
 
   llvm_unreachable("Unhandled cast kind!");
@@ -1490,6 +1494,17 @@
 
   case ObjCMessageExprClass: {
     const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(this);
+    if (Ctx.getLangOptions().ObjCAutoRefCount &&
+        ME->isInstanceMessage() &&
+        !ME->getType()->isVoidType() &&
+        ME->getSelector().getIdentifierInfoForSlot(0) &&
+        ME->getSelector().getIdentifierInfoForSlot(0)
+                                               ->getName().startswith("init")) {
+      Loc = getExprLoc();
+      R1 = ME->getSourceRange();
+      return true;
+    }
+
     const ObjCMethodDecl *MD = ME->getMethodDecl();
     if (MD && MD->getAttr<WarnUnusedResultAttr>()) {
       Loc = getExprLoc();
@@ -2519,7 +2534,7 @@
          /*TypeDependent=*/false, /*ValueDependent=*/false,
          /*ContainsUnexpandedParameterPack=*/false),
     NumArgs(NumArgs), Kind(IsInstanceSuper? SuperInstance : SuperClass),
-    HasMethod(Method != 0), SuperLoc(SuperLoc),
+    HasMethod(Method != 0), IsDelegateInitCall(false), SuperLoc(SuperLoc),
     SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
                                                        : Sel.getAsOpaquePtr())),
     SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc) 
@@ -2540,7 +2555,8 @@
                                  SourceLocation RBracLoc)
   : Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, T->isDependentType(),
          T->isDependentType(), T->containsUnexpandedParameterPack()),
-    NumArgs(NumArgs), Kind(Class), HasMethod(Method != 0),
+    NumArgs(NumArgs), Kind(Class),
+    HasMethod(Method != 0), IsDelegateInitCall(false),
     SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
                                                        : Sel.getAsOpaquePtr())),
     SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc) 
@@ -2571,7 +2587,8 @@
   : Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, Receiver->isTypeDependent(),
          Receiver->isTypeDependent(),
          Receiver->containsUnexpandedParameterPack()),
-    NumArgs(NumArgs), Kind(Instance), HasMethod(Method != 0),
+    NumArgs(NumArgs), Kind(Instance),
+    HasMethod(Method != 0), IsDelegateInitCall(false),
     SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
                                                        : Sel.getAsOpaquePtr())),
     SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc) 
@@ -2702,6 +2719,19 @@
   return 0;
 }
 
+llvm::StringRef ObjCBridgedCastExpr::getBridgeKindName() const {
+  switch (getBridgeKind()) {
+  case OBC_Bridge:
+    return "__bridge";
+  case OBC_BridgeTransfer:
+    return "__bridge_transfer";
+  case OBC_BridgeRetained:
+    return "__bridge_retained";
+  }
+  
+  return "__bridge";
+}
+
 bool ChooseExpr::isConditionTrue(const ASTContext &C) const {
   return getCond()->EvaluateAsInt(C) != 0;
 }

Modified: cfe/trunk/lib/AST/ExprClassification.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprClassification.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprClassification.cpp (original)
+++ cfe/trunk/lib/AST/ExprClassification.cpp Wed Jun 15 18:02:42 2011
@@ -162,6 +162,7 @@
   case Expr::SizeOfPackExprClass:
   case Expr::SubstNonTypeTemplateParmPackExprClass:
   case Expr::AsTypeExprClass:
+  case Expr::ObjCIndirectCopyRestoreExprClass:
     return Cl::CL_PRValue;
 
     // Next come the complicated cases.
@@ -289,6 +290,7 @@
   case Expr::CXXDynamicCastExprClass:
   case Expr::CXXReinterpretCastExprClass:
   case Expr::CXXConstCastExprClass:
+  case Expr::ObjCBridgedCastExprClass:
     // Only in C++ can casts be interesting at all.
     if (!Lang.CPlusPlus) return Cl::CL_PRValue;
     return ClassifyUnnamed(Ctx, cast<ExplicitCastExpr>(E)->getTypeAsWritten());

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Wed Jun 15 18:02:42 2011
@@ -282,6 +282,17 @@
       return true;
     return false;
   }
+  bool VisitObjCIvarRefExpr(const ObjCIvarRefExpr *E) {
+    if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified())
+      return true;
+    return false;
+  }
+  bool VisitBlockDeclRefExpr (const BlockDeclRefExpr *E) {
+    if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified())
+      return true;
+    return false;
+  }
+
   // We don't want to evaluate BlockExprs multiple times, as they generate
   // a ton of code.
   bool VisitBlockExpr(const BlockExpr *E) { return true; }
@@ -1797,6 +1808,8 @@
   case CK_GetObjCProperty:
   case CK_LValueBitCast:
   case CK_UserDefinedConversion:
+  case CK_ObjCProduceObject:
+  case CK_ObjCConsumeObject:
     return false;
 
   case CK_LValueToRValue:
@@ -2301,6 +2314,8 @@
   case CK_FloatingComplexToBoolean:
   case CK_IntegralComplexToReal:
   case CK_IntegralComplexToBoolean:
+  case CK_ObjCProduceObject:
+  case CK_ObjCConsumeObject:
     llvm_unreachable("invalid cast kind for complex value");
 
   case CK_LValueToRValue:
@@ -2771,6 +2786,7 @@
   case Expr::PackExpansionExprClass:
   case Expr::SubstNonTypeTemplateParmPackExprClass:
   case Expr::AsTypeExprClass:
+  case Expr::ObjCIndirectCopyRestoreExprClass:
     return ICEDiag(2, E->getLocStart());
 
   case Expr::SizeOfPackExprClass:
@@ -2995,7 +3011,8 @@
   case Expr::CXXFunctionalCastExprClass:
   case Expr::CXXStaticCastExprClass:
   case Expr::CXXReinterpretCastExprClass:
-  case Expr::CXXConstCastExprClass: {
+  case Expr::CXXConstCastExprClass: 
+  case Expr::ObjCBridgedCastExprClass: {
     const Expr *SubExpr = cast<CastExpr>(E)->getSubExpr();
     if (SubExpr->getType()->isIntegralOrEnumerationType())
       return CheckICE(SubExpr, Ctx);

Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ItaniumMangle.cpp (original)
+++ cfe/trunk/lib/AST/ItaniumMangle.cpp Wed Jun 15 18:02:42 2011
@@ -21,6 +21,7 @@
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
 #include "clang/AST/TypeLoc.h"
 #include "clang/Basic/ABI.h"
 #include "clang/Basic/SourceManager.h"
@@ -1464,7 +1465,35 @@
     Out << 'U' << ASString.size() << ASString;
   }
   
-  // FIXME: For now, just drop all extension qualifiers on the floor.
+  llvm::StringRef LifetimeName;
+  switch (Quals.getObjCLifetime()) {
+  // Objective-C ARC Extension:
+  //
+  //   <type> ::= U "__strong"
+  //   <type> ::= U "__weak"
+  //   <type> ::= U "__autoreleasing"
+  //   <type> ::= U "__unsafe_unretained"
+  case Qualifiers::OCL_None:
+    break;
+    
+  case Qualifiers::OCL_Weak:
+    LifetimeName = "__weak";
+    break;
+    
+  case Qualifiers::OCL_Strong:
+    LifetimeName = "__strong";
+    break;
+    
+  case Qualifiers::OCL_Autoreleasing:
+    LifetimeName = "__autoreleasing";
+    break;
+    
+  case Qualifiers::OCL_ExplicitNone:
+    LifetimeName = "__unsafe_unretained";
+    break;
+  }
+  if (!LifetimeName.empty())
+    Out << 'U' << LifetimeName.size() << LifetimeName;
 }
 
 void CXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) {
@@ -2089,6 +2118,7 @@
   case Expr::ObjCProtocolExprClass:
   case Expr::ObjCSelectorExprClass:
   case Expr::ObjCStringLiteralClass:
+  case Expr::ObjCIndirectCopyRestoreExprClass:
   case Expr::OffsetOfExprClass:
   case Expr::PredefinedExprClass:
   case Expr::ShuffleVectorExprClass:
@@ -2347,7 +2377,15 @@
     mangleExpression(cast<ImplicitCastExpr>(E)->getSubExpr(), Arity);
     break;
   }
-
+      
+  case Expr::ObjCBridgedCastExprClass: {
+    // Mangle ownership casts as a vendor extended operator __bridge, 
+    // __bridge_transfer, or __bridge_retain.
+    llvm::StringRef Kind = cast<ObjCBridgedCastExpr>(E)->getBridgeKindName();
+    Out << "v1U" << Kind.size() << Kind;
+  }
+  // Fall through to mangle the cast itself.
+      
   case Expr::CStyleCastExprClass:
   case Expr::CXXStaticCastExprClass:
   case Expr::CXXDynamicCastExprClass:

Modified: cfe/trunk/lib/AST/ParentMap.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ParentMap.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ParentMap.cpp (original)
+++ cfe/trunk/lib/AST/ParentMap.cpp Wed Jun 15 18:02:42 2011
@@ -66,6 +66,15 @@
   return S;  
 }
 
+Stmt *ParentMap::getOuterParenParent(Stmt *S) const {
+  Stmt *Paren = 0;
+  while (isa<ParenExpr>(S)) {
+    Paren = S;
+    S = getParent(S);
+  };
+  return Paren;
+}
+
 bool ParentMap::isConsumedExpr(Expr* E) const {
   Stmt *P = getParent(E);
   Stmt *DirectChild = E;

Modified: cfe/trunk/lib/AST/StmtPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Wed Jun 15 18:02:42 2011
@@ -449,6 +449,12 @@
   OS << "\n";
 }
 
+void StmtPrinter::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *Node) {
+  Indent() << "@autoreleasepool";
+  PrintRawCompoundStmt(dyn_cast<CompoundStmt>(Node->getSubStmt()));
+  OS << "\n";
+}
+
 void StmtPrinter::PrintRawCXXCatchStmt(CXXCatchStmt *Node) {
   OS << "catch (";
   if (Decl *ExDecl = Node->getExceptionDecl())
@@ -1464,6 +1470,17 @@
   OS << "]";
 }
 
+void
+StmtPrinter::VisitObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) {
+  PrintExpr(E->getSubExpr());
+}
+
+void
+StmtPrinter::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
+  OS << "(" << E->getBridgeKindName() << E->getType().getAsString(Policy) 
+     << ")";
+  PrintExpr(E->getSubExpr());
+}
 
 void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
   BlockDecl *BD = Node->getBlockDecl();

Modified: cfe/trunk/lib/AST/StmtProfile.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtProfile.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtProfile.cpp (original)
+++ cfe/trunk/lib/AST/StmtProfile.cpp Wed Jun 15 18:02:42 2011
@@ -220,6 +220,10 @@
   VisitStmt(S);
 }
 
+void StmtProfiler::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
+  VisitStmt(S);
+}
+
 void StmtProfiler::VisitExpr(Expr *S) {
   VisitStmt(S);
 }
@@ -952,6 +956,17 @@
   ID.AddBoolean(S->isArrow());
 }
 
+void
+StmtProfiler::VisitObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *S) {
+  VisitExpr(S);
+  ID.AddBoolean(S->shouldCopy());
+}
+
+void StmtProfiler::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *S) {
+  VisitExplicitCastExpr(S);
+  ID.AddBoolean(S->getBridgeKind());
+}
+
 void StmtProfiler::VisitDecl(Decl *D) {
   ID.AddInteger(D? D->getKind() : 0);
 

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Wed Jun 15 18:02:42 2011
@@ -36,7 +36,10 @@
      (hasObjCGCAttr() && !Other.hasObjCGCAttr())) &&
     // Address space superset.
     ((getAddressSpace() == Other.getAddressSpace()) ||
-     (hasAddressSpace()&& !Other.hasAddressSpace()));
+     (hasAddressSpace()&& !Other.hasAddressSpace())) &&
+    // Lifetime qualifier superset.
+    ((getObjCLifetime() == Other.getObjCLifetime()) ||
+     (hasObjCLifetime() && !Other.hasObjCLifetime()));
 }
 
 bool QualType::isConstant(QualType T, ASTContext &Ctx) {
@@ -866,39 +869,59 @@
   }
 }
 
-/// isPODType - Return true if this is a plain-old-data type (C++ 3.9p10)
-bool Type::isPODType() const {
+bool QualType::isPODType(ASTContext &Context) const {
   // The compiler shouldn't query this for incomplete types, but the user might.
   // We return false for that case. Except for incomplete arrays of PODs, which
   // are PODs according to the standard.
-  if (isIncompleteArrayType() &&
-      cast<ArrayType>(CanonicalType)->getElementType()->isPODType())
-    return true;
-  if (isIncompleteType())
+  if (isNull())
+    return 0;
+  
+  if ((*this)->isIncompleteArrayType())
+    return Context.getBaseElementType(*this).isPODType(Context);
+    
+  if ((*this)->isIncompleteType())
     return false;
 
+  if (Context.getLangOptions().ObjCAutoRefCount) {
+    switch (getObjCLifetime()) {
+    case Qualifiers::OCL_ExplicitNone:
+      return true;
+      
+    case Qualifiers::OCL_Strong:
+    case Qualifiers::OCL_Weak:
+    case Qualifiers::OCL_Autoreleasing:
+      return false;
+
+    case Qualifiers::OCL_None:
+      if ((*this)->isObjCLifetimeType())
+        return false;
+      break;
+    }        
+  }
+  
+  QualType CanonicalType = getTypePtr()->CanonicalType;
   switch (CanonicalType->getTypeClass()) {
     // Everything not explicitly mentioned is not POD.
   default: return false;
-  case VariableArray:
-  case ConstantArray:
+  case Type::VariableArray:
+  case Type::ConstantArray:
     // IncompleteArray is handled above.
-    return cast<ArrayType>(CanonicalType)->getElementType()->isPODType();
-
-  case Builtin:
-  case Complex:
-  case Pointer:
-  case MemberPointer:
-  case Vector:
-  case ExtVector:
-  case ObjCObjectPointer:
-  case BlockPointer:
+    return Context.getBaseElementType(*this).isPODType(Context);
+        
+  case Type::ObjCObjectPointer:
+  case Type::BlockPointer:
+  case Type::Builtin:
+  case Type::Complex:
+  case Type::Pointer:
+  case Type::MemberPointer:
+  case Type::Vector:
+  case Type::ExtVector:
     return true;
 
-  case Enum:
+  case Type::Enum:
     return true;
 
-  case Record:
+  case Type::Record:
     if (CXXRecordDecl *ClassDecl
           = dyn_cast<CXXRecordDecl>(cast<RecordType>(CanonicalType)->getDecl()))
       return ClassDecl->isPOD();
@@ -908,6 +931,121 @@
   }
 }
 
+bool QualType::isTrivialType(ASTContext &Context) const {
+  // The compiler shouldn't query this for incomplete types, but the user might.
+  // We return false for that case. Except for incomplete arrays of PODs, which
+  // are PODs according to the standard.
+  if (isNull())
+    return 0;
+  
+  if ((*this)->isArrayType())
+    return Context.getBaseElementType(*this).isTrivialType(Context);
+  
+  // Return false for incomplete types after skipping any incomplete array
+  // types which are expressly allowed by the standard and thus our API.
+  if ((*this)->isIncompleteType())
+    return false;
+  
+  if (Context.getLangOptions().ObjCAutoRefCount) {
+    switch (getObjCLifetime()) {
+    case Qualifiers::OCL_ExplicitNone:
+      return true;
+      
+    case Qualifiers::OCL_Strong:
+    case Qualifiers::OCL_Weak:
+    case Qualifiers::OCL_Autoreleasing:
+      return false;
+      
+    case Qualifiers::OCL_None:
+      if ((*this)->isObjCLifetimeType())
+        return false;
+      break;
+    }        
+  }
+  
+  QualType CanonicalType = getTypePtr()->CanonicalType;
+  if (CanonicalType->isDependentType())
+    return false;
+  
+  // C++0x [basic.types]p9:
+  //   Scalar types, trivial class types, arrays of such types, and
+  //   cv-qualified versions of these types are collectively called trivial
+  //   types.
+  
+  // As an extension, Clang treats vector types as Scalar types.
+  if (CanonicalType->isScalarType() || CanonicalType->isVectorType())
+    return true;
+  if (const RecordType *RT = CanonicalType->getAs<RecordType>()) {
+    if (const CXXRecordDecl *ClassDecl =
+        dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+      // C++0x [class]p5:
+      //   A trivial class is a class that has a trivial default constructor
+      if (!ClassDecl->hasTrivialDefaultConstructor()) return false;
+      //   and is trivially copyable.
+      if (!ClassDecl->isTriviallyCopyable()) return false;
+    }
+    
+    return true;
+  }
+  
+  // No other types can match.
+  return false;
+}
+
+bool QualType::isTriviallyCopyableType(ASTContext &Context) const {
+  if ((*this)->isArrayType())
+    return Context.getBaseElementType(*this).isTrivialType(Context);
+
+  if (Context.getLangOptions().ObjCAutoRefCount) {
+    switch (getObjCLifetime()) {
+    case Qualifiers::OCL_ExplicitNone:
+      return true;
+      
+    case Qualifiers::OCL_Strong:
+    case Qualifiers::OCL_Weak:
+    case Qualifiers::OCL_Autoreleasing:
+      return false;
+      
+    case Qualifiers::OCL_None:
+      if ((*this)->isObjCLifetimeType())
+        return false;
+      break;
+    }        
+  }
+
+  // C++0x [basic.types]p9
+  //   Scalar types, trivially copyable class types, arrays of such types, and
+  //   cv-qualified versions of these types are collectively called trivial
+  //   types.
+
+  QualType CanonicalType = getCanonicalType();
+  if (CanonicalType->isDependentType())
+    return false;
+
+  // Return false for incomplete types after skipping any incomplete array types
+  // which are expressly allowed by the standard and thus our API.
+  if (CanonicalType->isIncompleteType())
+    return false;
+ 
+  // As an extension, Clang treats vector types as Scalar types.
+  if (CanonicalType->isScalarType() || CanonicalType->isVectorType())
+    return true;
+
+  if (const RecordType *RT = CanonicalType->getAs<RecordType>()) {
+    if (const CXXRecordDecl *ClassDecl =
+          dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+      if (!ClassDecl->isTriviallyCopyable()) return false;
+    }
+
+    return true;
+  }
+
+  // No other types can match.
+  return false;
+}
+
+
+
 bool Type::isLiteralType() const {
   if (isDependentType())
     return false;
@@ -928,6 +1066,10 @@
   if (BaseTy->isIncompleteType())
     return false;
 
+  // Objective-C lifetime types are not literal types.
+  if (BaseTy->isObjCRetainableType())
+    return false;
+  
   // C++0x [basic.types]p10:
   //   A type is a literal type if it is:
   //    -- a scalar type; or
@@ -961,68 +1103,6 @@
   return false;
 }
 
-bool Type::isTrivialType() const {
-  if (isDependentType())
-    return false;
-
-  // C++0x [basic.types]p9:
-  //   Scalar types, trivial class types, arrays of such types, and
-  //   cv-qualified versions of these types are collectively called trivial
-  //   types.
-  const Type *BaseTy = getBaseElementTypeUnsafe();
-  assert(BaseTy && "NULL element type");
-
-  // Return false for incomplete types after skipping any incomplete array
-  // types which are expressly allowed by the standard and thus our API.
-  if (BaseTy->isIncompleteType())
-    return false;
-
-  // As an extension, Clang treats vector types as Scalar types.
-  if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true;
-  if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
-    if (const CXXRecordDecl *ClassDecl =
-        dyn_cast<CXXRecordDecl>(RT->getDecl())) {
-      if (!ClassDecl->isTrivial()) return false;
-    }
-
-    return true;
-  }
-
-  // No other types can match.
-  return false;
-}
-
-bool Type::isTriviallyCopyableType() const {
-  if (isDependentType())
-    return false;
-
-  // C++0x [basic.types]p9
-  //   Scalar types, trivially copyable class types, arrays of such types, and
-  //   cv-qualified versions of these types are collectively called trivial
-  //   types.
-  const Type *BaseTy = getBaseElementTypeUnsafe();
-  assert(BaseTy && "NULL element type");
-
-  // Return false for incomplete types after skipping any incomplete array types
-  // which are expressly allowed by the standard and thus our API.
-  if (BaseTy->isIncompleteType())
-    return false;
- 
-  // As an extension, Clang treats vector types as Scalar types.
-  if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true;
-  if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
-    if (const CXXRecordDecl *ClassDecl =
-        dyn_cast<CXXRecordDecl>(RT->getDecl())) {
-      if (!ClassDecl->isTriviallyCopyable()) return false;
-    }
-
-    return true;
-  }
-
-  // No other types can match.
-  return false;
-}
-
 bool Type::isStandardLayoutType() const {
   if (isDependentType())
     return false;
@@ -1060,14 +1140,32 @@
 // This is effectively the intersection of isTrivialType and
 // isStandardLayoutType. We implement it dircetly to avoid redundant
 // conversions from a type to a CXXRecordDecl.
-bool Type::isCXX11PODType() const {
-  if (isDependentType())
+bool QualType::isCXX11PODType(ASTContext &Context) const {
+  const Type *ty = getTypePtr();
+  if (ty->isDependentType())
     return false;
 
+  if (Context.getLangOptions().ObjCAutoRefCount) {
+    switch (getObjCLifetime()) {
+    case Qualifiers::OCL_ExplicitNone:
+      return true;
+      
+    case Qualifiers::OCL_Strong:
+    case Qualifiers::OCL_Weak:
+    case Qualifiers::OCL_Autoreleasing:
+      return false;
+
+    case Qualifiers::OCL_None:
+      if (ty->isObjCLifetimeType())
+        return false;
+      break;
+    }        
+  }
+
   // C++11 [basic.types]p9:
   //   Scalar types, POD classes, arrays of such types, and cv-qualified
   //   versions of these types are collectively called trivial types.
-  const Type *BaseTy = getBaseElementTypeUnsafe();
+  const Type *BaseTy = ty->getBaseElementTypeUnsafe();
   assert(BaseTy && "NULL element type");
 
   // Return false for incomplete types after skipping any incomplete array
@@ -1392,7 +1490,8 @@
                  result->containsUnexpandedParameterPack(),
                  epi.ExtInfo),
     NumArgs(numArgs), NumExceptions(epi.NumExceptions),
-    ExceptionSpecType(epi.ExceptionSpecType)
+    ExceptionSpecType(epi.ExceptionSpecType),
+    HasAnyConsumedArgs(epi.ConsumedArguments != 0)
 {
   // Fill in the trailing argument array.
   QualType *argSlot = reinterpret_cast<QualType*>(this+1);
@@ -1423,6 +1522,12 @@
     Expr **noexSlot = reinterpret_cast<Expr**>(argSlot + numArgs);
     *noexSlot = epi.NoexceptExpr;
   }
+
+  if (epi.ConsumedArguments) {
+    bool *consumedArgs = const_cast<bool*>(getConsumedArgsBuffer());
+    for (unsigned i = 0; i != numArgs; ++i)
+      consumedArgs[i] = epi.ConsumedArguments[i];
+  }
 }
 
 FunctionProtoType::NoexceptResult
@@ -1461,6 +1566,24 @@
                                 const QualType *ArgTys, unsigned NumArgs,
                                 const ExtProtoInfo &epi,
                                 const ASTContext &Context) {
+
+  // We have to be careful not to get ambiguous profile encodings.
+  // Note that valid type pointers are never ambiguous with anything else.
+  //
+  // The encoding grammar begins:
+  //      type type* bool int bool 
+  // If that final bool is true, then there is a section for the EH spec:
+  //      bool type*
+  // This is followed by an optional "consumed argument" section of the
+  // same length as the first type sequence:
+  //      bool*
+  // Finally, we have the ext info:
+  //      int
+  // 
+  // There is no ambiguity between the consumed arguments and an empty EH
+  // spec because of the leading 'bool' which unambiguously indicates
+  // whether the following bool is the EH spec or part of the arguments.
+
   ID.AddPointer(Result.getAsOpaquePtr());
   for (unsigned i = 0; i != NumArgs; ++i)
     ID.AddPointer(ArgTys[i].getAsOpaquePtr());
@@ -1474,6 +1597,10 @@
   } else if (epi.ExceptionSpecType == EST_ComputedNoexcept && epi.NoexceptExpr){
     epi.NoexceptExpr->Profile(ID, Context, false);
   }
+  if (epi.ConsumedArguments) {
+    for (unsigned i = 0; i != NumArgs; ++i)
+      ID.AddBoolean(epi.ConsumedArguments[i]);
+  }
   epi.ExtInfo.Profile(ID);
 }
 
@@ -1900,6 +2027,79 @@
     CanonicalType->TypeBits.CacheValidAndVisibility = 0;
 }
 
+Qualifiers::ObjCLifetime Type::getObjCARCImplicitLifetime() const {
+  if (isObjCARCImplicitlyUnretainedType())
+    return Qualifiers::OCL_ExplicitNone;
+  return Qualifiers::OCL_Strong;
+}
+
+bool Type::isObjCARCImplicitlyUnretainedType() const {
+  assert(isObjCLifetimeType() &&
+         "cannot query implicit lifetime for non-inferrable type");
+
+  const Type *canon = getCanonicalTypeInternal().getTypePtr();
+
+  // Walk down to the base type.  We don't care about qualifiers for this.
+  while (const ArrayType *array = dyn_cast<ArrayType>(canon))
+    canon = array->getElementType().getTypePtr();
+
+  if (const ObjCObjectPointerType *opt
+        = dyn_cast<ObjCObjectPointerType>(canon)) {
+    // Class and Class<Protocol> don't require retension.
+    if (opt->getObjectType()->isObjCClass())
+      return true;
+  }
+
+  return false;
+}
+
+bool Type::isObjCNSObjectType() const {
+  if (const TypedefType *typedefType = dyn_cast<TypedefType>(this))
+    return typedefType->getDecl()->hasAttr<ObjCNSObjectAttr>();
+  return false;
+}
+bool Type::isObjCRetainableType() const {
+  return isObjCObjectPointerType() ||
+         isBlockPointerType() ||
+         isObjCNSObjectType();
+}
+bool Type::isObjCIndirectLifetimeType() const {
+  if (isObjCLifetimeType())
+    return true;
+  if (const PointerType *OPT = getAs<PointerType>())
+    return OPT->getPointeeType()->isObjCIndirectLifetimeType();
+  if (const ReferenceType *Ref = getAs<ReferenceType>())
+    return Ref->getPointeeType()->isObjCIndirectLifetimeType();
+  if (const MemberPointerType *MemPtr = getAs<MemberPointerType>())
+    return MemPtr->getPointeeType()->isObjCIndirectLifetimeType();
+  return false;
+}
+
+/// Returns true if objects of this type have lifetime semantics under
+/// ARC.
+bool Type::isObjCLifetimeType() const {
+  const Type *type = this;
+  while (const ArrayType *array = type->getAsArrayTypeUnsafe())
+    type = array->getElementType().getTypePtr();
+  return type->isObjCRetainableType();
+}
+
+/// \brief Determine whether the given type T is a "bridgable" Objective-C type,
+/// which is either an Objective-C object pointer type or an 
+bool Type::isObjCARCBridgableType() const {
+  return isObjCObjectPointerType() || isBlockPointerType();
+}
+
+/// \brief Determine whether the given type T is a "bridgeable" C type.
+bool Type::isCARCBridgableType() const {
+  const PointerType *Pointer = getAs<PointerType>();
+  if (!Pointer)
+    return false;
+  
+  QualType Pointee = Pointer->getPointeeType();
+  return Pointee->isVoidType() || Pointee->isRecordType();
+}
+
 bool Type::hasSizedVLAType() const {
   if (!isVariablyModifiedType()) return false;
 
@@ -1919,6 +2119,18 @@
 }
 
 QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) {
+  switch (type.getObjCLifetime()) {
+  case Qualifiers::OCL_None:
+  case Qualifiers::OCL_ExplicitNone:
+  case Qualifiers::OCL_Autoreleasing:
+    break;
+
+  case Qualifiers::OCL_Strong:
+    return DK_objc_strong_lifetime;
+  case Qualifiers::OCL_Weak:
+    return DK_objc_weak_lifetime;
+  }
+
   /// Currently, the only destruction kind we recognize is C++ objects
   /// with non-trivial destructors.
   const CXXRecordDecl *record =
@@ -1928,3 +2140,24 @@
 
   return DK_none;
 }
+
+bool QualType::hasTrivialCopyAssignment(ASTContext &Context) const {
+  switch (getObjCLifetime()) {
+  case Qualifiers::OCL_None:
+    break;
+      
+  case Qualifiers::OCL_ExplicitNone:
+    return true;
+      
+  case Qualifiers::OCL_Autoreleasing:
+  case Qualifiers::OCL_Strong:
+  case Qualifiers::OCL_Weak:
+    return !Context.getLangOptions().ObjCAutoRefCount;
+  }
+  
+  if (const CXXRecordDecl *Record 
+            = getTypePtr()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl())
+    return Record->hasTrivialCopyAssignment();
+  
+  return true;
+}

Modified: cfe/trunk/lib/AST/TypePrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypePrinter.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/AST/TypePrinter.cpp (original)
+++ cfe/trunk/lib/AST/TypePrinter.cpp Wed Jun 15 18:02:42 2011
@@ -24,6 +24,23 @@
 using namespace clang;
 
 namespace {
+  /// \brief RAII object that enables printing of the ARC __strong lifetime
+  /// qualifier.
+  class IncludeStrongLifetimeRAII {
+    PrintingPolicy &Policy;
+    bool Old;
+    
+  public:
+    explicit IncludeStrongLifetimeRAII(PrintingPolicy &Policy) 
+      : Policy(Policy), Old(Policy.SuppressStrongLifetime) {
+      Policy.SuppressStrongLifetime = false;
+    }
+    
+    ~IncludeStrongLifetimeRAII() {
+      Policy.SuppressStrongLifetime = Old;
+    }
+  };
+  
   class TypePrinter {
     PrintingPolicy Policy;
 
@@ -78,7 +95,7 @@
   // "int * const", printing "const int *" is different.  Only do this when the
   // type expands to a simple string.
   bool CanPrefixQualifiers = false;
-  
+  bool NeedARCStrongQualifier = false;
   Type::TypeClass TC = T->getTypeClass();
   if (const AutoType *AT = dyn_cast<AutoType>(T))
     TC = AT->desugar()->getTypeClass();
@@ -114,15 +131,18 @@
         T->isObjCQualifiedIdType() || T->isObjCQualifiedClassType();
       break;
       
+    case Type::ConstantArray:
+    case Type::IncompleteArray:
+    case Type::VariableArray:
+    case Type::DependentSizedArray:
+      NeedARCStrongQualifier = true;
+      // Fall through
+      
     case Type::Pointer:
     case Type::BlockPointer:
     case Type::LValueReference:
     case Type::RValueReference:
     case Type::MemberPointer:
-    case Type::ConstantArray:
-    case Type::IncompleteArray:
-    case Type::VariableArray:
-    case Type::DependentSizedArray:
     case Type::DependentSizedExtVector:
     case Type::Vector:
     case Type::ExtVector:
@@ -139,13 +159,20 @@
   
   if (!CanPrefixQualifiers && !Quals.empty()) {
     std::string qualsBuffer;
-    Quals.getAsStringInternal(qualsBuffer, Policy);
+    if (NeedARCStrongQualifier) {
+      IncludeStrongLifetimeRAII Strong(Policy);
+      Quals.getAsStringInternal(qualsBuffer, Policy);
+    } else {
+      Quals.getAsStringInternal(qualsBuffer, Policy);
+    }
     
-    if (!buffer.empty()) {
-      qualsBuffer += ' ';
-      qualsBuffer += buffer;
+    if (!qualsBuffer.empty()) {
+      if (!buffer.empty()) {
+        qualsBuffer += ' ';
+        qualsBuffer += buffer;
+      }
+      std::swap(buffer, qualsBuffer);
     }
-    std::swap(buffer, qualsBuffer);
   }
   
   switch (T->getTypeClass()) {
@@ -159,13 +186,20 @@
   // If we're adding the qualifiers as a prefix, do it now.
   if (CanPrefixQualifiers && !Quals.empty()) {
     std::string qualsBuffer;
-    Quals.getAsStringInternal(qualsBuffer, Policy);
-    
-    if (!buffer.empty()) {
-      qualsBuffer += ' ';
-      qualsBuffer += buffer;
+    if (NeedARCStrongQualifier) {
+      IncludeStrongLifetimeRAII Strong(Policy);
+      Quals.getAsStringInternal(qualsBuffer, Policy);
+    } else {
+      Quals.getAsStringInternal(qualsBuffer, Policy);
+    }
+
+    if (!qualsBuffer.empty()) {
+      if (!buffer.empty()) {
+        qualsBuffer += ' ';
+        qualsBuffer += buffer;
+      }
+      std::swap(buffer, qualsBuffer);
     }
-    std::swap(buffer, qualsBuffer);
   }
 }
 
@@ -192,6 +226,7 @@
   if (isa<ArrayType>(T->getPointeeType()))
     S = '(' + S + ')';
   
+  IncludeStrongLifetimeRAII Strong(Policy);
   print(T->getPointeeType(), S);
 }
 
@@ -209,6 +244,7 @@
   if (isa<ArrayType>(T->getPointeeTypeAsWritten()))
     S = '(' + S + ')';
   
+  IncludeStrongLifetimeRAII Strong(Policy);
   print(T->getPointeeTypeAsWritten(), S);
 }
 
@@ -221,6 +257,7 @@
   if (isa<ArrayType>(T->getPointeeTypeAsWritten()))
     S = '(' + S + ')';
   
+  IncludeStrongLifetimeRAII Strong(Policy);
   print(T->getPointeeTypeAsWritten(), S);
 }
 
@@ -236,6 +273,7 @@
   if (isa<ArrayType>(T->getPointeeType()))
     S = '(' + S + ')';
   
+  IncludeStrongLifetimeRAII Strong(Policy);
   print(T->getPointeeType(), S);
 }
 
@@ -245,12 +283,14 @@
   S += llvm::utostr(T->getSize().getZExtValue());
   S += ']';
   
+  IncludeStrongLifetimeRAII Strong(Policy);
   print(T->getElementType(), S);
 }
 
 void TypePrinter::printIncompleteArray(const IncompleteArrayType *T, 
                                        std::string &S) {
   S += "[]";
+  IncludeStrongLifetimeRAII Strong(Policy);
   print(T->getElementType(), S);
 }
 
@@ -276,6 +316,7 @@
   }
   S += ']';
   
+  IncludeStrongLifetimeRAII Strong(Policy);
   print(T->getElementType(), S);
 }
 
@@ -291,6 +332,7 @@
   }
   S += ']';
   
+  IncludeStrongLifetimeRAII Strong(Policy);
   print(T->getElementType(), S);
 }
 
@@ -518,6 +560,7 @@
   if (!S.empty())
     S = ' ' + S;
   std::string Str;
+  IncludeStrongLifetimeRAII Strong(Policy);
   print(T->getBaseType(), Str);
 
   switch (T->getUTTKind()) {
@@ -552,6 +595,7 @@
       Buffer += "<anonymous>";
   } else if (ClassTemplateSpecializationDecl *Spec
                = dyn_cast<ClassTemplateSpecializationDecl>(DC)) {
+    IncludeStrongLifetimeRAII Strong(Policy);
     const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
     std::string TemplateArgsStr
       = TemplateSpecializationType::PrintTemplateArgumentList(
@@ -642,6 +686,7 @@
       Args = TemplateArgs.data();
       NumArgs = TemplateArgs.size();
     }
+    IncludeStrongLifetimeRAII Strong(Policy);
     Buffer += TemplateSpecializationType::PrintTemplateArgumentList(Args,
                                                                     NumArgs,
                                                                     Policy);
@@ -677,18 +722,21 @@
 
 void TypePrinter::printSubstTemplateTypeParm(const SubstTemplateTypeParmType *T, 
                                              std::string &S) { 
+  IncludeStrongLifetimeRAII Strong(Policy);
   print(T->getReplacementType(), S);
 }
 
 void TypePrinter::printSubstTemplateTypeParmPack(
                                         const SubstTemplateTypeParmPackType *T, 
                                              std::string &S) { 
+  IncludeStrongLifetimeRAII Strong(Policy);
   printTemplateTypeParm(T->getReplacedParameter(), S);
 }
 
 void TypePrinter::printTemplateSpecialization(
                                             const TemplateSpecializationType *T, 
                                               std::string &S) { 
+  IncludeStrongLifetimeRAII Strong(Policy);
   std::string SpecString;
   
   {
@@ -765,6 +813,7 @@
 
 void TypePrinter::printDependentTemplateSpecialization(
         const DependentTemplateSpecializationType *T, std::string &S) { 
+  IncludeStrongLifetimeRAII Strong(Policy);
   std::string MyString;
   {
     llvm::raw_string_ostream OS(MyString);
@@ -796,8 +845,9 @@
 
 void TypePrinter::printAttributed(const AttributedType *T,
                                   std::string &S) {
-  // Prefer the macro forms of the GC qualifiers.
-  if (T->getAttrKind() == AttributedType::attr_objc_gc)
+  // Prefer the macro forms of the GC and lifetime qualifiers.
+  if (T->getAttrKind() == AttributedType::attr_objc_gc ||
+      T->getAttrKind() == AttributedType::attr_objc_lifetime)
     return print(T->getEquivalentType(), S);
 
   print(T->getModifiedType(), S);
@@ -866,6 +916,18 @@
     break;
   }
 
+  case AttributedType::attr_objc_lifetime:
+    S += "objc_lifetime(";
+    switch (T->getEquivalentType().getObjCLifetime()) {
+    case Qualifiers::OCL_None: llvm_unreachable("no lifetime!"); break;
+    case Qualifiers::OCL_ExplicitNone: S += "none"; break;
+    case Qualifiers::OCL_Strong: S += "strong"; break;
+    case Qualifiers::OCL_Weak: S += "weak"; break;
+    case Qualifiers::OCL_Autoreleasing: S += "autoreleasing"; break;
+    }
+    S += ")";
+    break;
+
   case AttributedType::attr_noreturn: S += "noreturn"; break;
   case AttributedType::attr_cdecl: S += "cdecl"; break;
   case AttributedType::attr_fastcall: S += "fastcall"; break;
@@ -1080,7 +1142,7 @@
 // prefix a space if the string is non-empty.  Will not append a final
 // space.
 void Qualifiers::getAsStringInternal(std::string &S,
-                                     const PrintingPolicy&) const {
+                                     const PrintingPolicy& Policy) const {
   AppendTypeQualList(S, getCVRQualifiers());
   if (unsigned addrspace = getAddressSpace()) {
     if (!S.empty()) S += ' ';
@@ -1095,6 +1157,23 @@
     else
       S += "__strong";
   }
+  if (Qualifiers::ObjCLifetime lifetime = getObjCLifetime()) {
+    if (!S.empty() && 
+        !(lifetime == Qualifiers::OCL_Strong && Policy.SuppressStrongLifetime))
+      S += ' ';
+    
+    switch (lifetime) {
+    case Qualifiers::OCL_None: llvm_unreachable("none but true");
+    case Qualifiers::OCL_ExplicitNone: S += "__unsafe_unretained"; break;
+    case Qualifiers::OCL_Strong: 
+      if (!Policy.SuppressStrongLifetime)
+        S += "__strong"; 
+      break;
+        
+    case Qualifiers::OCL_Weak: S += "__weak"; break;
+    case Qualifiers::OCL_Autoreleasing: S += "__autoreleasing"; break;
+    }
+  }
 }
 
 std::string QualType::getAsString(const Type *ty, Qualifiers qs) {

Modified: cfe/trunk/lib/Analysis/ReachableCode.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ReachableCode.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ReachableCode.cpp (original)
+++ cfe/trunk/lib/Analysis/ReachableCode.cpp Wed Jun 15 18:02:42 2011
@@ -16,6 +16,7 @@
 #include "llvm/ADT/SmallVector.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
 #include "clang/AST/StmtCXX.h"
 #include "clang/Analysis/Analyses/ReachableCode.h"
 #include "clang/Analysis/CFG.h"
@@ -108,6 +109,11 @@
     case Stmt::CXXTryStmtClass: {
       return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc();
     }
+    case Expr::ObjCBridgedCastExprClass: {
+      const ObjCBridgedCastExpr *CSC = cast<ObjCBridgedCastExpr>(S);
+      R1 = CSC->getSubExpr()->getSourceRange();
+      return CSC->getLParenLoc();
+    }
     default: ;
   }
   R1 = S->getSourceRange();

Modified: cfe/trunk/lib/Basic/DiagnosticIDs.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/DiagnosticIDs.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/DiagnosticIDs.cpp (original)
+++ cfe/trunk/lib/Basic/DiagnosticIDs.cpp Wed Jun 15 18:02:42 2011
@@ -740,5 +740,10 @@
       DiagID == diag::err_unavailable_message)
     return false;
 
+  // Currently we consider all ARC errors as recoverable.
+  if (getCategoryNumberForDiag(DiagID) ==
+        diag::DiagCat_Automatic_Reference_Counting_Issue)
+    return false;
+
   return true;
 }

Modified: cfe/trunk/lib/Basic/IdentifierTable.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/IdentifierTable.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/IdentifierTable.cpp (original)
+++ cfe/trunk/lib/Basic/IdentifierTable.cpp Wed Jun 15 18:02:42 2011
@@ -17,6 +17,7 @@
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
 #include "llvm/Support/raw_ostream.h"
 #include <cstdio>
 
@@ -92,7 +93,8 @@
     KEYBORLAND = 0x100,
     KEYOPENCL = 0x200,
     KEYC1X = 0x400,
-    KEYALL = 0x7ff
+    KEYARC = 0x800,
+    KEYALL = 0x0fff
   };
 }
 
@@ -120,7 +122,8 @@
   else if (LangOpts.OpenCL && (Flags & KEYOPENCL)) AddResult = 2;
   else if (!LangOpts.CPlusPlus && (Flags & KEYNOCXX)) AddResult = 2;
   else if (LangOpts.C1X && (Flags & KEYC1X)) AddResult = 2;
-
+  else if (LangOpts.ObjCAutoRefCount && (Flags & KEYARC)) AddResult = 2;
+           
   // Don't add this keyword if disabled in this language.
   if (AddResult == 0) return;
 

Modified: cfe/trunk/lib/Basic/Targets.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Targets.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/Targets.cpp (original)
+++ cfe/trunk/lib/Basic/Targets.cpp Wed Jun 15 18:02:42 2011
@@ -84,15 +84,35 @@
   Builder.defineMacro("__MACH__");
   Builder.defineMacro("OBJC_NEW_PROPERTIES");
 
-  // __weak is always defined, for use in blocks and with objc pointers.
-  Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))");
-
-  // Darwin defines __strong even in C mode (just to nothing).
-  if (!Opts.ObjC1 || Opts.getGCMode() == LangOptions::NonGC)
-    Builder.defineMacro("__strong", "");
-  else
-    Builder.defineMacro("__strong", "__attribute__((objc_gc(strong)))");
+  if (Opts.ObjCAutoRefCount) {
+    Builder.defineMacro("__weak", "__attribute__((objc_lifetime(weak)))");
+    Builder.defineMacro("__strong", "__attribute__((objc_lifetime(strong)))");
+    Builder.defineMacro("__autoreleasing",
+                        "__attribute__((objc_lifetime(autoreleasing)))");
+    Builder.defineMacro("__unsafe_unretained",
+                        "__attribute__((objc_lifetime(none)))");
+  } else {
+    // __weak is always defined, for use in blocks and with objc pointers.
+    Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))");
 
+    // Darwin defines __strong even in C mode (just to nothing).
+    if (Opts.getGCMode() != LangOptions::NonGC)
+      Builder.defineMacro("__strong", "__attribute__((objc_gc(strong)))");
+    else
+      Builder.defineMacro("__strong", "");
+    
+    // __unsafe_unretained is defined to nothing in non-ARC mode. We even
+    // allow this in C, since one might have block pointers in structs that
+    // are used in pure C code and in Objective-C ARC.
+    Builder.defineMacro("__unsafe_unretained", "");
+    
+    // The Objective-C bridged cast keywords are defined to nothing in non-ARC
+    // mode; then they become normal, C-style casts.
+    Builder.defineMacro("__bridge", "");
+    Builder.defineMacro("__bridge_transfer", "");
+    Builder.defineMacro("__bridge_retained", "");
+  }
+  
   if (Opts.Static)
     Builder.defineMacro("__STATIC__");
   else

Modified: cfe/trunk/lib/CodeGen/CGBlocks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBlocks.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGBlocks.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGBlocks.cpp Wed Jun 15 18:02:42 2011
@@ -347,13 +347,23 @@
       continue;
     }
 
-    // Block pointers require copy/dispose.
-    if (variable->getType()->isBlockPointerType()) {
-      info.NeedsCopyDispose = true;
+    // If we have a lifetime qualifier, honor it for capture purposes.
+    // That includes *not* copying it if it's __unsafe_unretained.
+    if (Qualifiers::ObjCLifetime lifetime 
+          = variable->getType().getObjCLifetime()) {
+      switch (lifetime) {
+      case Qualifiers::OCL_None: llvm_unreachable("impossible");
+      case Qualifiers::OCL_ExplicitNone:
+      case Qualifiers::OCL_Autoreleasing:
+        break;
+
+      case Qualifiers::OCL_Strong:
+      case Qualifiers::OCL_Weak:
+        info.NeedsCopyDispose = true;
+      }
 
-    // So do Objective-C pointers.
-    } else if (variable->getType()->isObjCObjectPointerType() ||
-               C.isObjCNSObjectType(variable->getType())) {
+    // Block pointers require copy/dispose.  So do Objective-C pointers.
+    } else if (variable->getType()->isObjCRetainableType()) {
       info.NeedsCopyDispose = true;
 
     // So do types that require non-trivial copy construction.
@@ -591,6 +601,11 @@
 
     // Otherwise, fake up a POD copy into the block field.
     } else {
+      // Fake up a new variable so that EmitScalarInit doesn't think
+      // we're referring to the variable in its own initializer.
+      ImplicitParamDecl blockFieldPseudoVar(/*DC*/ 0, SourceLocation(),
+                                            /*name*/ 0, type);
+
       // We use one of these or the other depending on whether the
       // reference is nested.
       DeclRefExpr notNested(const_cast<VarDecl*>(variable), type, VK_LValue,
@@ -603,15 +618,29 @@
 
       ImplicitCastExpr l2r(ImplicitCastExpr::OnStack, type, CK_LValueToRValue,
                            declRef, VK_RValue);
-      EmitExprAsInit(&l2r, variable, blockField,
+      EmitExprAsInit(&l2r, &blockFieldPseudoVar, blockField,
                      getContext().getDeclAlign(variable),
                      /*captured by init*/ false);
     }
 
     // Push a destructor if necessary.  The semantics for when this
     // actually gets run are really obscure.
-    if (!ci->isByRef() && CGM.getLangOptions().CPlusPlus)
-      PushDestructorCleanup(type, blockField);
+    if (!ci->isByRef()) {
+      switch (type.isDestructedType()) {
+      case QualType::DK_none:
+        break;
+      case QualType::DK_cxx_destructor:
+        PushDestructorCleanup(type, blockField);
+        break;
+      case QualType::DK_objc_strong_lifetime:
+        PushARCReleaseCleanup(getARCCleanupKind(), type, blockField, false);
+        break;
+      case QualType::DK_objc_weak_lifetime:
+        // __weak objects on the stack always get EH cleanups.
+        PushARCWeakReleaseCleanup(NormalAndEHCleanup, type, blockField);
+        break;
+      }
+    }
   }
 
   // Cast to the converted block-pointer type, which happens (somewhat
@@ -1023,8 +1052,6 @@
 
 
 
-
-
 llvm::Constant *
 CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
   ASTContext &C = getContext();
@@ -1084,21 +1111,40 @@
     if (capture.isConstant()) continue;
 
     const Expr *copyExpr = ci->getCopyExpr();
-    unsigned flags = 0;
+    BlockFieldFlags flags;
+
+    bool isARCWeakCapture = false;
 
     if (copyExpr) {
       assert(!ci->isByRef());
       // don't bother computing flags
+
     } else if (ci->isByRef()) {
       flags = BLOCK_FIELD_IS_BYREF;
-      if (type.isObjCGCWeak()) flags |= BLOCK_FIELD_IS_WEAK;
-    } else if (type->isBlockPointerType()) {
-      flags = BLOCK_FIELD_IS_BLOCK;
-    } else if (type->isObjCObjectPointerType() || C.isObjCNSObjectType(type)) {
+      if (type.isObjCGCWeak())
+        flags |= BLOCK_FIELD_IS_WEAK;
+
+    } else if (type->isObjCRetainableType()) {
       flags = BLOCK_FIELD_IS_OBJECT;
-    }
+      if (type->isBlockPointerType())
+        flags = BLOCK_FIELD_IS_BLOCK;
 
-    if (!copyExpr && !flags) continue;
+      // Special rules for ARC captures:
+      if (getLangOptions().ObjCAutoRefCount) {
+        Qualifiers qs = type.getQualifiers();
+
+        // Don't generate special copy logic for a captured object
+        // unless it's __strong or __weak.
+        if (!qs.hasStrongOrWeakObjCLifetime())
+          continue;
+
+        // Support __weak direct captures.
+        if (qs.getObjCLifetime() == Qualifiers::OCL_Weak)
+          isARCWeakCapture = true;
+      }
+    } else {
+      continue;
+    }
 
     unsigned index = capture.getIndex();
     llvm::Value *srcField = Builder.CreateStructGEP(src, index);
@@ -1107,12 +1153,14 @@
     // If there's an explicit copy expression, we do that.
     if (copyExpr) {
       EmitSynthesizedCXXCopyCtor(dstField, srcField, copyExpr);
+    } else if (isARCWeakCapture) {
+      EmitARCCopyWeak(dstField, srcField);
     } else {
       llvm::Value *srcValue = Builder.CreateLoad(srcField, "blockcopy.src");
       srcValue = Builder.CreateBitCast(srcValue, VoidPtrTy);
       llvm::Value *dstAddr = Builder.CreateBitCast(dstField, VoidPtrTy);
       Builder.CreateCall3(CGM.getBlockObjectAssign(), dstAddr, srcValue,
-                          llvm::ConstantInt::get(Int32Ty, flags));
+                          llvm::ConstantInt::get(Int32Ty, flags.getBitMask()));
     }
   }
 
@@ -1176,20 +1224,37 @@
     BlockFieldFlags flags;
     const CXXDestructorDecl *dtor = 0;
 
+    bool isARCWeakCapture = false;
+
     if (ci->isByRef()) {
       flags = BLOCK_FIELD_IS_BYREF;
-      if (type.isObjCGCWeak()) flags |= BLOCK_FIELD_IS_WEAK;
-    } else if (type->isBlockPointerType()) {
-      flags = BLOCK_FIELD_IS_BLOCK;
-    } else if (type->isObjCObjectPointerType() || C.isObjCNSObjectType(type)) {
+      if (type.isObjCGCWeak())
+        flags |= BLOCK_FIELD_IS_WEAK;
+    } else if (const CXXRecordDecl *record = type->getAsCXXRecordDecl()) {
+      if (record->hasTrivialDestructor())
+        continue;
+      dtor = record->getDestructor();
+    } else if (type->isObjCRetainableType()) {
       flags = BLOCK_FIELD_IS_OBJECT;
-    } else if (C.getLangOptions().CPlusPlus) {
-      if (const CXXRecordDecl *record = type->getAsCXXRecordDecl())
-        if (!record->hasTrivialDestructor())
-          dtor = record->getDestructor();
-    }
+      if (type->isBlockPointerType())
+        flags = BLOCK_FIELD_IS_BLOCK;
 
-    if (!dtor && flags.empty()) continue;
+      // Special rules for ARC captures.
+      if (getLangOptions().ObjCAutoRefCount) {
+        Qualifiers qs = type.getQualifiers();
+
+        // Don't generate special dispose logic for a captured object
+        // unless it's __strong or __weak.
+        if (!qs.hasStrongOrWeakObjCLifetime())
+          continue;
+
+        // Support __weak direct captures.
+        if (qs.getObjCLifetime() == Qualifiers::OCL_Weak)
+          isARCWeakCapture = true;
+      }
+    } else {
+      continue;
+    }
 
     unsigned index = capture.getIndex();
     llvm::Value *srcField = Builder.CreateStructGEP(src, index);
@@ -1198,6 +1263,10 @@
     if (dtor) {
       PushDestructorCleanup(dtor, srcField);
 
+    // If this is a __weak capture, emit the release directly.
+    } else if (isARCWeakCapture) {
+      EmitARCDestroyWeak(srcField);
+
     // Otherwise we call _Block_object_dispose.  It wouldn't be too
     // hard to just emit this as a cleanup if we wanted to make sure
     // that things were done in reverse.
@@ -1251,6 +1320,55 @@
   }
 };
 
+/// Emits the copy/dispose helpers for an ARC __block __weak variable.
+class ARCWeakByrefHelpers : public CodeGenModule::ByrefHelpers {
+public:
+  ARCWeakByrefHelpers(CharUnits alignment) : ByrefHelpers(alignment) {}
+
+  void emitCopy(CodeGenFunction &CGF, llvm::Value *destField,
+                llvm::Value *srcField) {
+    CGF.EmitARCMoveWeak(destField, srcField);
+  }
+
+  void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
+    CGF.EmitARCDestroyWeak(field);
+  }
+
+  void profileImpl(llvm::FoldingSetNodeID &id) const {
+    // 0 is distinguishable from all pointers and byref flags
+    id.AddInteger(0);
+  }
+};
+
+/// Emits the copy/dispose helpers for an ARC __block __strong variable
+/// that's not of block-pointer type.
+class ARCStrongByrefHelpers : public CodeGenModule::ByrefHelpers {
+public:
+  ARCStrongByrefHelpers(CharUnits alignment) : ByrefHelpers(alignment) {}
+
+  void emitCopy(CodeGenFunction &CGF, llvm::Value *destField,
+                llvm::Value *srcField) {
+    // Do a "move" by copying the value and then zeroing out the old
+    // variable.
+
+    llvm::Value *value = CGF.Builder.CreateLoad(srcField);
+    llvm::Value *null =
+      llvm::ConstantPointerNull::get(cast<llvm::PointerType>(value->getType()));
+    CGF.Builder.CreateStore(value, destField);
+    CGF.Builder.CreateStore(null, srcField);
+  }
+
+  void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
+    llvm::Value *value = CGF.Builder.CreateLoad(field);
+    CGF.EmitARCRelease(value, /*precise*/ false);
+  }
+
+  void profileImpl(llvm::FoldingSetNodeID &id) const {
+    // 1 is distinguishable from all pointers and byref flags
+    id.AddInteger(1);
+  }
+};
+
 /// Emits the copy/dispose helpers for a __block variable with a
 /// nontrivial copy constructor or destructor.
 class CXXByrefHelpers : public CodeGenModule::ByrefHelpers {
@@ -1318,6 +1436,7 @@
                                           SC_Static,
                                           SC_None,
                                           false, true);
+
   CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation());
 
   if (byrefInfo.needsCopy()) {
@@ -1449,6 +1568,52 @@
     return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
   }
 
+  // Otherwise, if we don't have a retainable type, there's nothing to do.
+  // that the runtime does extra copies.
+  if (!type->isObjCRetainableType()) return 0;
+
+  Qualifiers qs = type.getQualifiers();
+
+  // If we have lifetime, that dominates.
+  if (Qualifiers::ObjCLifetime lifetime = qs.getObjCLifetime()) {
+    assert(getLangOptions().ObjCAutoRefCount);
+
+    switch (lifetime) {
+    case Qualifiers::OCL_None: llvm_unreachable("impossible");
+
+    // These are just bits as far as the runtime is concerned.
+    case Qualifiers::OCL_ExplicitNone:
+    case Qualifiers::OCL_Autoreleasing:
+      return 0;
+
+    // Tell the runtime that this is ARC __weak, called by the
+    // byref routines.
+    case Qualifiers::OCL_Weak: {
+      ARCWeakByrefHelpers byrefInfo(emission.Alignment);
+      return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
+    }
+
+    // ARC __strong __block variables need to be retained.
+    case Qualifiers::OCL_Strong:
+      // Block-pointers need to be _Block_copy'ed, so we let the
+      // runtime be in charge.  But we can't use the code below
+      // because we don't want to set BYREF_CALLER, which will
+      // just make the runtime ignore us.
+      if (type->isBlockPointerType()) {
+        BlockFieldFlags flags = BLOCK_FIELD_IS_BLOCK;
+        ObjectByrefHelpers byrefInfo(emission.Alignment, flags);
+        return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
+
+      // Otherwise, we transfer ownership of the retain from the stack
+      // to the heap.
+      } else {
+        ARCStrongByrefHelpers byrefInfo(emission.Alignment);
+        return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
+      }
+    }
+    llvm_unreachable("fell out of lifetime switch!");
+  }
+
   BlockFieldFlags flags;
   if (type->isBlockPointerType()) {
     flags |= BLOCK_FIELD_IS_BLOCK;
@@ -1639,6 +1804,7 @@
     CallBlockRelease(llvm::Value *Addr) : Addr(Addr) {}
 
     void Emit(CodeGenFunction &CGF, bool IsForEH) {
+      // Should we be passing FIELD_IS_WEAK here?
       CGF.BuildBlockRelease(Addr, BLOCK_FIELD_IS_BYREF);
     }
   };

Modified: cfe/trunk/lib/CodeGen/CGBlocks.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBlocks.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGBlocks.h (original)
+++ cfe/trunk/lib/CodeGen/CGBlocks.h Wed Jun 15 18:02:42 2011
@@ -89,7 +89,7 @@
                                     variable */
   BLOCK_FIELD_IS_WEAK     = 0x10,  /* declared __weak, only used in byref copy
                                     helpers */
-
+  BLOCK_FIELD_IS_ARC      = 0x40,  /* field has ARC-specific semantics */
   BLOCK_BYREF_CALLER      = 128,   /* called from __block (byref) copy/dispose
                                       support routines */
   BLOCK_BYREF_CURRENT_MAX = 256

Modified: cfe/trunk/lib/CodeGen/CGCall.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCall.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCall.cpp Wed Jun 15 18:02:42 2011
@@ -25,6 +25,7 @@
 #include "llvm/Attributes.h"
 #include "llvm/Support/CallSite.h"
 #include "llvm/Target/TargetData.h"
+#include "llvm/InlineAsm.h"
 #include "llvm/Transforms/Utils/Local.h"
 using namespace clang;
 using namespace CodeGen;
@@ -190,13 +191,15 @@
          e = MD->param_end(); i != e; ++i) {
     ArgTys.push_back(Context.getCanonicalParamType((*i)->getType()));
   }
-  return getFunctionInfo(GetReturnType(MD->getResultType()),
-                         ArgTys,
-                         FunctionType::ExtInfo(
-                             /*NoReturn*/ false,
-                             /*HasRegParm*/ false,
-                             /*RegParm*/ 0,
-                             getCallingConventionForDecl(MD)));
+
+  FunctionType::ExtInfo einfo;
+  einfo = einfo.withCallingConv(getCallingConventionForDecl(MD));
+
+  if (getContext().getLangOptions().ObjCAutoRefCount &&
+      MD->hasAttr<NSReturnsRetainedAttr>())
+    einfo = einfo.withProducesResult(true);
+
+  return getFunctionInfo(GetReturnType(MD->getResultType()), ArgTys, einfo);
 }
 
 const CGFunctionInfo &CodeGenTypes::getFunctionInfo(GlobalDecl GD) {
@@ -262,7 +265,8 @@
     return *FI;
 
   // Construct the function info.
-  FI = new CGFunctionInfo(CC, Info.getNoReturn(), Info.getHasRegParm(), Info.getRegParm(), ResTy,
+  FI = new CGFunctionInfo(CC, Info.getNoReturn(), Info.getProducesResult(),
+                          Info.getHasRegParm(), Info.getRegParm(), ResTy,
                           ArgTys.data(), ArgTys.size());
   FunctionInfos.InsertNode(FI, InsertPos);
 
@@ -291,13 +295,15 @@
 }
 
 CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention,
-                               bool _NoReturn, bool _HasRegParm, unsigned _RegParm,
+                               bool _NoReturn, bool returnsRetained,
+                               bool _HasRegParm, unsigned _RegParm,
                                CanQualType ResTy,
                                const CanQualType *ArgTys,
                                unsigned NumArgTys)
   : CallingConvention(_CallingConvention),
     EffectiveCallingConvention(_CallingConvention),
-    NoReturn(_NoReturn), HasRegParm(_HasRegParm), RegParm(_RegParm)
+    NoReturn(_NoReturn), ReturnsRetained(returnsRetained),
+    HasRegParm(_HasRegParm), RegParm(_RegParm)
 {
   NumArgs = NumArgTys;
 
@@ -1068,6 +1074,95 @@
   assert(AI == Fn->arg_end() && "Argument mismatch!");
 }
 
+/// Try to emit a fused autorelease of a return result.
+static llvm::Value *tryEmitFusedAutoreleaseOfResult(CodeGenFunction &CGF,
+                                                    llvm::Value *result) {
+  // We must be immediately followed the cast.
+  llvm::BasicBlock *BB = CGF.Builder.GetInsertBlock();
+  if (BB->empty()) return 0;
+  if (&BB->back() != result) return 0;
+
+  const llvm::Type *resultType = result->getType();
+
+  // result is in a BasicBlock and is therefore an Instruction.
+  llvm::Instruction *generator = cast<llvm::Instruction>(result);
+
+  llvm::SmallVector<llvm::Instruction*,4> insnsToKill;
+
+  // Look for:
+  //  %generator = bitcast %type1* %generator2 to %type2*
+  while (llvm::BitCastInst *bitcast = dyn_cast<llvm::BitCastInst>(generator)) {
+    // We would have emitted this as a constant if the operand weren't
+    // an Instruction.
+    generator = cast<llvm::Instruction>(bitcast->getOperand(0));
+
+    // Require the generator to be immediately followed by the cast.
+    if (generator->getNextNode() != bitcast)
+      return 0;
+
+    insnsToKill.push_back(bitcast);
+  }
+
+  // Look for:
+  //   %generator = call i8* @objc_retain(i8* %originalResult)
+  // or
+  //   %generator = call i8* @objc_retainAutoreleasedReturnValue(i8* %originalResult)
+  llvm::CallInst *call = dyn_cast<llvm::CallInst>(generator);
+  if (!call) return 0;
+
+  bool doRetainAutorelease;
+
+  if (call->getCalledValue() == CGF.CGM.getARCEntrypoints().objc_retain) {
+    doRetainAutorelease = true;
+  } else if (call->getCalledValue() == CGF.CGM.getARCEntrypoints()
+                                          .objc_retainAutoreleasedReturnValue) {
+    doRetainAutorelease = false;
+
+    // Look for an inline asm immediately preceding the call and kill it, too.
+    llvm::Instruction *prev = call->getPrevNode();
+    if (llvm::CallInst *asmCall = dyn_cast_or_null<llvm::CallInst>(prev))
+      if (asmCall->getCalledValue()
+            == CGF.CGM.getARCEntrypoints().retainAutoreleasedReturnValueMarker)
+        insnsToKill.push_back(prev);
+  } else {
+    return 0;
+  }
+
+  result = call->getArgOperand(0);
+  insnsToKill.push_back(call);
+
+  // Keep killing bitcasts, for sanity.  Note that we no longer care
+  // about precise ordering as long as there's exactly one use.
+  while (llvm::BitCastInst *bitcast = dyn_cast<llvm::BitCastInst>(result)) {
+    if (!bitcast->hasOneUse()) break;
+    insnsToKill.push_back(bitcast);
+    result = bitcast->getOperand(0);
+  }
+
+  // Delete all the unnecessary instructions, from latest to earliest.
+  for (llvm::SmallVectorImpl<llvm::Instruction*>::iterator
+         i = insnsToKill.begin(), e = insnsToKill.end(); i != e; ++i)
+    (*i)->eraseFromParent();
+
+  // Do the fused retain/autorelease if we were asked to.
+  if (doRetainAutorelease)
+    result = CGF.EmitARCRetainAutoreleaseReturnValue(result);
+
+  // Cast back to the result type.
+  return CGF.Builder.CreateBitCast(result, resultType);
+}
+
+/// Emit an ARC autorelease of the result of a function.
+static llvm::Value *emitAutoreleaseOfResult(CodeGenFunction &CGF,
+                                            llvm::Value *result) {
+  // At -O0, try to emit a fused retain/autorelease.
+  if (CGF.shouldUseFusedARCCalls())
+    if (llvm::Value *fused = tryEmitFusedAutoreleaseOfResult(CGF, result))
+      return fused;
+
+  return CGF.EmitARCAutoreleaseReturnValue(result);
+}
+
 void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
   // Functions with no result always return void.
   if (ReturnValue == 0) {
@@ -1135,6 +1230,16 @@
 
       RV = CreateCoercedLoad(V, RetAI.getCoerceToType(), *this);
     }
+
+    // In ARC, end functions that return a retainable type with a call
+    // to objc_autoreleaseReturnValue.
+    if (AutoreleaseResult) {
+      assert(getLangOptions().ObjCAutoRefCount &&
+             !FI.isReturnsRetained() &&
+             RetTy->isObjCRetainableType());
+      RV = emitAutoreleaseOfResult(*this, RV);
+    }
+
     break;
 
   case ABIArgInfo::Ignore:
@@ -1184,8 +1289,152 @@
   return args.add(RValue::get(value), type);
 }
 
+static bool isProvablyNull(llvm::Value *addr) {
+  return isa<llvm::ConstantPointerNull>(addr);
+}
+
+static bool isProvablyNonNull(llvm::Value *addr) {
+  return isa<llvm::AllocaInst>(addr);
+}
+
+/// Emit the actual writing-back of a writeback.
+static void emitWriteback(CodeGenFunction &CGF,
+                          const CallArgList::Writeback &writeback) {
+  llvm::Value *srcAddr = writeback.Address;
+  assert(!isProvablyNull(srcAddr) &&
+         "shouldn't have writeback for provably null argument");
+
+  llvm::BasicBlock *contBB = 0;
+
+  // If the argument wasn't provably non-null, we need to null check
+  // before doing the store.
+  bool provablyNonNull = isProvablyNonNull(srcAddr);
+  if (!provablyNonNull) {
+    llvm::BasicBlock *writebackBB = CGF.createBasicBlock("icr.writeback");
+    contBB = CGF.createBasicBlock("icr.done");
+
+    llvm::Value *isNull = CGF.Builder.CreateIsNull(srcAddr, "icr.isnull");
+    CGF.Builder.CreateCondBr(isNull, contBB, writebackBB);
+    CGF.EmitBlock(writebackBB);
+  }
+
+  // Load the value to writeback.
+  llvm::Value *value = CGF.Builder.CreateLoad(writeback.Temporary);
+
+  // Cast it back, in case we're writing an id to a Foo* or something.
+  value = CGF.Builder.CreateBitCast(value,
+               cast<llvm::PointerType>(srcAddr->getType())->getElementType(),
+                            "icr.writeback-cast");
+  
+  // Perform the writeback.
+  QualType srcAddrType = writeback.AddressType;
+  CGF.EmitStoreThroughLValue(RValue::get(value),
+                             CGF.MakeAddrLValue(srcAddr, srcAddrType),
+                             srcAddrType);
+
+  // Jump to the continuation block.
+  if (!provablyNonNull)
+    CGF.EmitBlock(contBB);
+}
+
+static void emitWritebacks(CodeGenFunction &CGF,
+                           const CallArgList &args) {
+  for (CallArgList::writeback_iterator
+         i = args.writeback_begin(), e = args.writeback_end(); i != e; ++i)
+    emitWriteback(CGF, *i);
+}
+
+/// Emit an argument that's being passed call-by-writeback.  That is,
+/// we are passing the address of 
+static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
+                             const ObjCIndirectCopyRestoreExpr *CRE) {
+  llvm::Value *srcAddr = CGF.EmitScalarExpr(CRE->getSubExpr());
+
+  // The dest and src types don't necessarily match in LLVM terms
+  // because of the crazy ObjC compatibility rules.
+
+  const llvm::PointerType *destType =
+    cast<llvm::PointerType>(CGF.ConvertType(CRE->getType()));
+
+  // If the address is a constant null, just pass the appropriate null.
+  if (isProvablyNull(srcAddr)) {
+    args.add(RValue::get(llvm::ConstantPointerNull::get(destType)),
+             CRE->getType());
+    return;
+  }
+
+  QualType srcAddrType =
+    CRE->getSubExpr()->getType()->castAs<PointerType>()->getPointeeType();
+
+  // Create the temporary.
+  llvm::Value *temp = CGF.CreateTempAlloca(destType->getElementType(),
+                                           "icr.temp");
+
+  // Zero-initialize it if we're not doing a copy-initialization.
+  bool shouldCopy = CRE->shouldCopy();
+  if (!shouldCopy) {
+    llvm::Value *null =
+      llvm::ConstantPointerNull::get(
+        cast<llvm::PointerType>(destType->getElementType()));
+    CGF.Builder.CreateStore(null, temp);
+  }
+
+  llvm::BasicBlock *contBB = 0;
+
+  // If the address is *not* known to be non-null, we need to switch.
+  llvm::Value *finalArgument;
+
+  bool provablyNonNull = isProvablyNonNull(srcAddr);
+  if (provablyNonNull) {
+    finalArgument = temp;
+  } else {
+    llvm::Value *isNull = CGF.Builder.CreateIsNull(srcAddr, "icr.isnull");
+
+    finalArgument = CGF.Builder.CreateSelect(isNull, 
+                                   llvm::ConstantPointerNull::get(destType),
+                                             temp, "icr.argument");
+
+    // If we need to copy, then the load has to be conditional, which
+    // means we need control flow.
+    if (shouldCopy) {
+      contBB = CGF.createBasicBlock("icr.cont");
+      llvm::BasicBlock *copyBB = CGF.createBasicBlock("icr.copy");
+      CGF.Builder.CreateCondBr(isNull, contBB, copyBB);
+      CGF.EmitBlock(copyBB);
+    }
+  }
+
+  // Perform a copy if necessary.
+  if (shouldCopy) {
+    LValue srcLV = CGF.MakeAddrLValue(srcAddr, srcAddrType);
+    RValue srcRV = CGF.EmitLoadOfLValue(srcLV, srcAddrType);
+    assert(srcRV.isScalar());
+
+    llvm::Value *src = srcRV.getScalarVal();
+    src = CGF.Builder.CreateBitCast(src, destType->getElementType(),
+                                    "icr.cast");
+
+    // Use an ordinary store, not a store-to-lvalue.
+    CGF.Builder.CreateStore(src, temp);
+  }
+
+  // Finish the control flow if we needed it.
+  if (shouldCopy && !provablyNonNull)
+    CGF.EmitBlock(contBB);
+
+  args.addWriteback(srcAddr, srcAddrType, temp);
+  args.add(RValue::get(finalArgument), CRE->getType());
+}
+
 void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
                                   QualType type) {
+  if (const ObjCIndirectCopyRestoreExpr *CRE
+        = dyn_cast<ObjCIndirectCopyRestoreExpr>(E)) {
+    assert(getContext().getLangOptions().ObjCAutoRefCount);
+    assert(getContext().hasSameType(E->getType(), type));
+    return emitWritebackArg(*this, args, CRE);
+  }
+
   if (type->isReferenceType())
     return args.add(EmitReferenceBindingToExpr(E, /*InitializedDecl=*/0),
                     type);
@@ -1435,6 +1684,11 @@
   if (Builder.isNamePreserving() && !CI->getType()->isVoidTy())
     CI->setName("call");
 
+  // Emit any writebacks immediately.  Arguably this should happen
+  // after any return-value munging.
+  if (CallArgs.hasWritebacks())
+    emitWritebacks(*this, CallArgs);
+
   switch (RetAI.getKind()) {
   case ABIArgInfo::Indirect: {
     unsigned Alignment = getContext().getTypeAlignInChars(RetTy).getQuantity();

Modified: cfe/trunk/lib/CodeGen/CGCall.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCall.h (original)
+++ cfe/trunk/lib/CodeGen/CGCall.h Wed Jun 15 18:02:42 2011
@@ -58,9 +58,44 @@
   class CallArgList :
     public llvm::SmallVector<CallArg, 16> {
   public:
+    struct Writeback {
+      /// The original argument.
+      llvm::Value *Address;
+
+      /// The pointee type of the original argument.
+      QualType AddressType;
+
+      /// The temporary alloca.
+      llvm::Value *Temporary;
+    };
+
     void add(RValue rvalue, QualType type, bool needscopy = false) {
       push_back(CallArg(rvalue, type, needscopy));
     }
+
+    void addFrom(const CallArgList &other) {
+      insert(end(), other.begin(), other.end());
+      Writebacks.insert(Writebacks.end(),
+                        other.Writebacks.begin(), other.Writebacks.end());
+    }
+
+    void addWriteback(llvm::Value *address, QualType addressType,
+                      llvm::Value *temporary) {
+      Writeback writeback;
+      writeback.Address = address;
+      writeback.AddressType = addressType;
+      writeback.Temporary = temporary;
+      Writebacks.push_back(writeback);
+    }
+
+    bool hasWritebacks() const { return !Writebacks.empty(); }
+
+    typedef llvm::SmallVectorImpl<Writeback>::const_iterator writeback_iterator;
+    writeback_iterator writeback_begin() const { return Writebacks.begin(); }
+    writeback_iterator writeback_end() const { return Writebacks.end(); }
+
+  private:
+    llvm::SmallVector<Writeback, 1> Writebacks;
   };
 
   /// FunctionArgList - Type for representing both the decl and type
@@ -88,6 +123,9 @@
     /// Whether this function is noreturn.
     bool NoReturn;
 
+    /// Whether this function is returns-retained.
+    bool ReturnsRetained;
+
     unsigned NumArgs;
     ArgInfo *Args;
 
@@ -100,7 +138,8 @@
     typedef ArgInfo *arg_iterator;
 
     CGFunctionInfo(unsigned CallingConvention, bool NoReturn,
-                   bool HasRegParm, unsigned RegParm, CanQualType ResTy,
+                   bool ReturnsRetained, bool HasRegParm, unsigned RegParm,
+                   CanQualType ResTy,
                    const CanQualType *ArgTys, unsigned NumArgTys);
     ~CGFunctionInfo() { delete[] Args; }
 
@@ -113,6 +152,10 @@
 
     bool isNoReturn() const { return NoReturn; }
 
+    /// In ARR, whether this function retains its return value.  This
+    /// is not always reliable for call sites.
+    bool isReturnsRetained() const { return ReturnsRetained; }
+
     /// getCallingConvention - Return the user specified calling
     /// convention.
     unsigned getCallingConvention() const { return CallingConvention; }
@@ -137,6 +180,7 @@
     void Profile(llvm::FoldingSetNodeID &ID) {
       ID.AddInteger(getCallingConvention());
       ID.AddBoolean(NoReturn);
+      ID.AddBoolean(ReturnsRetained);
       ID.AddBoolean(HasRegParm);
       ID.AddInteger(RegParm);
       getReturnType().Profile(ID);
@@ -151,6 +195,7 @@
                         Iterator end) {
       ID.AddInteger(Info.getCC());
       ID.AddBoolean(Info.getNoReturn());
+      ID.AddBoolean(Info.getProducesResult());
       ID.AddBoolean(Info.getHasRegParm());
       ID.AddInteger(Info.getRegParm());
       ResTy.Profile(ID);

Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Wed Jun 15 18:02:42 2011
@@ -398,7 +398,8 @@
                                               BaseClassDecl,
                                               isBaseVirtual);
 
-  AggValueSlot AggSlot = AggValueSlot::forAddr(V, false, /*Lifetime*/ true);
+  AggValueSlot AggSlot = AggValueSlot::forAddr(V, Qualifiers(), 
+                                               /*Lifetime*/ true);
 
   CGF.EmitAggExpr(BaseInit->getInit(), AggSlot);
   
@@ -428,10 +429,20 @@
       CGF.Builder.CreateStore(Next, ArrayIndexVar);      
     }
 
-    AggValueSlot Slot = AggValueSlot::forAddr(Dest, LHS.isVolatileQualified(),
-                                              /*Lifetime*/ true);
-    
-    CGF.EmitAggExpr(MemberInit->getInit(), Slot);
+    if (!CGF.hasAggregateLLVMType(T)) {
+      CGF.EmitScalarInit(MemberInit->getInit(), 0, Dest, false, 
+                         LHS.isVolatileQualified(), 
+                         CGF.getContext().getTypeAlign(T),
+                         T);
+    } else if (T->isAnyComplexType()) {
+      CGF.EmitComplexExprIntoAddr(MemberInit->getInit(), Dest, 
+                                  LHS.isVolatileQualified());
+    } else {    
+      AggValueSlot Slot = AggValueSlot::forAddr(Dest, LHS.getQuals(),
+                                                /*Lifetime*/ true);
+      
+      CGF.EmitAggExpr(MemberInit->getInit(), Slot);
+    }
     
     return;
   }
@@ -540,15 +551,16 @@
 
   // FIXME: If there's no initializer and the CXXCtorInitializer
   // was implicitly generated, we shouldn't be zeroing memory.
-  RValue RHS;
-  if (FieldType->isReferenceType()) {
-    RHS = CGF.EmitReferenceBindingToExpr(MemberInit->getInit(), Field);
-    CGF.EmitStoreThroughLValue(RHS, LHS, FieldType);
-  } else if (FieldType->isArrayType() && !MemberInit->getInit()) {
+  if (FieldType->isArrayType() && !MemberInit->getInit()) {
     CGF.EmitNullInitialization(LHS.getAddress(), Field->getType());
   } else if (!CGF.hasAggregateLLVMType(Field->getType())) {
-    RHS = RValue::get(CGF.EmitScalarExpr(MemberInit->getInit()));
-    CGF.EmitStoreThroughLValue(RHS, LHS, FieldType);
+    if (LHS.isSimple()) {
+      CGF.EmitExprAsInit(MemberInit->getInit(), Field, LHS.getAddress(),
+                         CGF.getContext().getDeclAlign(Field), false);
+    } else {
+      RValue RHS = RValue::get(CGF.EmitScalarExpr(MemberInit->getInit()));
+      CGF.EmitStoreThroughLValue(RHS, LHS, FieldType);
+    }
   } else if (MemberInit->getInit()->getType()->isAnyComplexType()) {
     CGF.EmitComplexExprIntoAddr(MemberInit->getInit(), LHS.getAddress(),
                                 LHS.isVolatileQualified());
@@ -576,11 +588,11 @@
       llvm::Value *Zero = llvm::Constant::getNullValue(SizeTy);
       CGF.Builder.CreateStore(Zero, ArrayIndexVar);
       
-      // If we are copying an array of scalars or classes with trivial copy 
+      // If we are copying an array of PODs or classes with trivial copy 
       // constructors, perform a single aggregate copy.
-      const RecordType *Record = BaseElementTy->getAs<RecordType>();
-      if (!Record || 
-          cast<CXXRecordDecl>(Record->getDecl())->hasTrivialCopyConstructor()) {
+      const CXXRecordDecl *Record = BaseElementTy->getAsCXXRecordDecl();
+      if (BaseElementTy.isPODType(CGF.getContext()) ||
+          (Record && Record->hasTrivialCopyConstructor())) {
         // Find the source pointer. We knows it's the last argument because
         // we know we're in a copy constructor.
         unsigned SrcArgIndex = Args.size() - 1;
@@ -925,12 +937,8 @@
     CallArrayFieldDtor(const FieldDecl *Field) : Field(Field) {}
 
     void Emit(CodeGenFunction &CGF, bool IsForEH) {
-      QualType FieldType = Field->getType();
-      const ConstantArrayType *Array =
-        CGF.getContext().getAsConstantArrayType(FieldType);
-      
-      QualType BaseType =
-        CGF.getContext().getBaseElementType(Array->getElementType());
+      QualType FieldType = Field->getType();      
+      QualType BaseType = CGF.getContext().getBaseElementType(FieldType);
       const CXXRecordDecl *FieldClassDecl = BaseType->getAsCXXRecordDecl();
 
       llvm::Value *ThisPtr = CGF.LoadCXXThis();
@@ -938,9 +946,12 @@
                                           // FIXME: Qualifiers?
                                           /*CVRQualifiers=*/0);
 
-      const llvm::Type *BasePtr = CGF.ConvertType(BaseType)->getPointerTo();
-      llvm::Value *BaseAddrPtr =
-        CGF.Builder.CreateBitCast(LHS.getAddress(), BasePtr);
+      const llvm::Type *BasePtr 
+        = CGF.ConvertType(BaseType)->getPointerTo();
+      llvm::Value *BaseAddrPtr
+        = CGF.Builder.CreateBitCast(LHS.getAddress(), BasePtr);
+      const ConstantArrayType *Array
+        = CGF.getContext().getAsConstantArrayType(FieldType);
       CGF.EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(),
                                     Array, BaseAddrPtr);
     }
@@ -1042,19 +1053,26 @@
       getContext().getAsConstantArrayType(FieldType);
     if (Array)
       FieldType = getContext().getBaseElementType(Array->getElementType());
-    
-    const RecordType *RT = FieldType->getAs<RecordType>();
-    if (!RT)
+
+    switch (FieldType.isDestructedType()) {
+    case QualType::DK_none:
       continue;
-    
-    CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
-    if (FieldClassDecl->hasTrivialDestructor())
-        continue;
+        
+    case QualType::DK_cxx_destructor:
+      if (Array)
+        EHStack.pushCleanup<CallArrayFieldDtor>(NormalAndEHCleanup, Field);
+      else
+        EHStack.pushCleanup<CallFieldDtor>(NormalAndEHCleanup, Field);
+      break;
+        
+    case QualType::DK_objc_strong_lifetime:
+      PushARCFieldReleaseCleanup(getARCCleanupKind(), Field);
+      break;
 
-    if (Array)
-      EHStack.pushCleanup<CallArrayFieldDtor>(NormalAndEHCleanup, Field);
-    else
-      EHStack.pushCleanup<CallFieldDtor>(NormalAndEHCleanup, Field);
+    case QualType::DK_objc_weak_lifetime:
+      PushARCFieldWeakReleaseCleanup(getARCCleanupKind(), Field);
+      break;
+    }
   }
 }
 
@@ -1384,7 +1402,8 @@
 
   llvm::Value *ThisPtr = LoadCXXThis();
 
-  AggValueSlot AggSlot = AggValueSlot::forAddr(ThisPtr, false, /*Lifetime*/ true);
+  AggValueSlot AggSlot =
+    AggValueSlot::forAddr(ThisPtr, Qualifiers(), /*Lifetime*/ true);
 
   EmitAggExpr(Ctor->init_begin()[0]->getInit(), AggSlot);
 

Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDebugInfo.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDebugInfo.cpp Wed Jun 15 18:02:42 2011
@@ -389,6 +389,7 @@
   // Ignore these qualifiers for now.
   Qc.removeObjCGCAttr();
   Qc.removeAddressSpace();
+  Qc.removeObjCLifetime();
 
   // We will create one Derived type for one qualifier and recurse to handle any
   // additional ones.

Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Wed Jun 15 18:02:42 2011
@@ -353,9 +353,7 @@
       if (NRVO) CGF.EmitBlock(SkipDtorBB);
     }
   };
-}
 
-namespace {
   struct CallStackRestore : EHScopeStack::Cleanup {
     llvm::Value *Stack;
     CallStackRestore(llvm::Value *Stack) : Stack(Stack) {}
@@ -400,6 +398,164 @@
   };
 }
 
+/// EmitAutoVarWithLifetime - Does the setup required for an automatic
+/// variable with lifetime.
+static void EmitAutoVarWithLifetime(CodeGenFunction &CGF, const VarDecl &var,
+                                    llvm::Value *addr,
+                                    Qualifiers::ObjCLifetime lifetime) {
+  switch (lifetime) {
+  case Qualifiers::OCL_None:
+    llvm_unreachable("present but none");
+
+  case Qualifiers::OCL_ExplicitNone:
+    // nothing to do
+    break;
+
+  case Qualifiers::OCL_Strong: {
+    CGF.PushARCReleaseCleanup(CGF.getARCCleanupKind(),
+                              var.getType(), addr,
+                              var.hasAttr<ObjCPreciseLifetimeAttr>());
+    break;
+  }
+  case Qualifiers::OCL_Autoreleasing:
+    // nothing to do
+    break;
+ 
+  case Qualifiers::OCL_Weak:
+    // __weak objects always get EH cleanups; otherwise, exceptions
+    // could cause really nasty crashes instead of mere leaks.
+    CGF.PushARCWeakReleaseCleanup(NormalAndEHCleanup, var.getType(), addr);
+    break;
+  }
+}
+
+static bool isAccessedBy(const VarDecl &var, const Stmt *s) {
+  if (const Expr *e = dyn_cast<Expr>(s)) {
+    // Skip the most common kinds of expressions that make
+    // hierarchy-walking expensive.
+    s = e = e->IgnoreParenCasts();
+
+    if (const DeclRefExpr *ref = dyn_cast<DeclRefExpr>(e))
+      return (ref->getDecl() == &var);
+  }
+
+  for (Stmt::const_child_range children = s->children(); children; ++children)
+    if (isAccessedBy(var, *children))
+      return true;
+
+  return false;
+}
+
+static bool isAccessedBy(const ValueDecl *decl, const Expr *e) {
+  if (!decl) return false;
+  if (!isa<VarDecl>(decl)) return false;
+  const VarDecl *var = cast<VarDecl>(decl);
+  return isAccessedBy(*var, e);
+}
+
+void CodeGenFunction::EmitScalarInit(const Expr *init,
+                                     const ValueDecl *D,
+                                     llvm::Value *addr, bool capturedByInit,
+                                     bool isVolatile, unsigned alignment, 
+                                     QualType type) {
+  Qualifiers::ObjCLifetime lifetime = type.getQualifiers().getObjCLifetime();
+  if (!lifetime) {
+    llvm::Value *value = EmitScalarExpr(init);
+    if (capturedByInit) addr = BuildBlockByrefAddress(addr, cast<VarDecl>(D));
+    EmitStoreOfScalar(value, addr, isVolatile, alignment, type);
+    return;
+  }
+
+  // If we're emitting a value with lifetime, we have to do the
+  // initialization *before* we leave the cleanup scopes.
+  CodeGenFunction::RunCleanupsScope Scope(*this);
+  if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(init))
+    init = ewc->getSubExpr();
+
+  // We have to maintain the illusion that the variable is
+  // zero-initialized.  If the variable might be accessed in its
+  // initializer, zero-initialize before running the initializer, then
+  // actually perform the initialization with an assign.
+  bool accessedByInit = false;
+  if (lifetime != Qualifiers::OCL_ExplicitNone)
+    accessedByInit = isAccessedBy(D, init);
+  if (accessedByInit) {
+    // Drill down to the __block object if necessary.
+    llvm::Value *tempAddr = addr;
+    if (capturedByInit) {
+      // We can use a simple GEP for this because it can't have been
+      // moved yet.
+      tempAddr = Builder.CreateStructGEP(tempAddr,
+                                   getByRefValueLLVMField(cast<VarDecl>(D)));
+    }
+
+    const llvm::PointerType *ty = cast<llvm::PointerType>(tempAddr->getType());
+    ty = cast<llvm::PointerType>(ty->getElementType());
+
+    llvm::Value *zero = llvm::ConstantPointerNull::get(ty);
+    
+    // If __weak, we want to use a barrier under certain conditions.
+    if (lifetime == Qualifiers::OCL_Weak)
+      EmitARCInitWeak(tempAddr, zero);
+
+    // Otherwise just do a simple store.
+    else
+      EmitStoreOfScalar(zero, tempAddr, isVolatile, alignment, type);
+  }
+
+  // Emit the initializer.
+  llvm::Value *value = 0;
+
+  switch (lifetime) {
+  case Qualifiers::OCL_None:
+    llvm_unreachable("present but none");
+
+  case Qualifiers::OCL_ExplicitNone:
+    // nothing to do
+    value = EmitScalarExpr(init);
+    break;
+
+  case Qualifiers::OCL_Strong: {
+    value = EmitARCRetainScalarExpr(init);
+    break;
+  }
+
+  case Qualifiers::OCL_Weak: {
+    // No way to optimize a producing initializer into this.  It's not
+    // worth optimizing for, because the value will immediately
+    // disappear in the common case.
+    value = EmitScalarExpr(init);
+
+    if (capturedByInit) addr = BuildBlockByrefAddress(addr, cast<VarDecl>(D));
+    if (accessedByInit)
+      EmitARCStoreWeak(addr, value, /*ignored*/ true);
+    else
+      EmitARCInitWeak(addr, value);
+    return;
+  }
+
+  case Qualifiers::OCL_Autoreleasing:
+    value = EmitARCRetainAutoreleaseScalarExpr(init);
+    break;
+  }
+
+  if (capturedByInit) addr = BuildBlockByrefAddress(addr, cast<VarDecl>(D));
+
+  llvm::MDNode *tbaa = CGM.getTBAAInfo(type);
+
+  // If the variable might have been accessed by its initializer, we
+  // might have to initialize with a barrier.  We have to do this for
+  // both __weak and __strong, but __weak got filtered out above.
+  if (accessedByInit && lifetime == Qualifiers::OCL_Strong) {
+    llvm::Value *oldValue
+      = EmitLoadOfScalar(addr, isVolatile, alignment, type, tbaa);
+    EmitStoreOfScalar(value, addr, isVolatile, alignment, type, tbaa);
+    EmitARCRelease(oldValue, /*precise*/ false);
+    return;
+  }
+
+  EmitStoreOfScalar(value, addr, isVolatile, alignment, type, tbaa);  
+}
 
 /// canEmitInitWithFewStoresAfterMemset - Decide whether we can emit the
 /// non-zero parts of the specified initializer with equal or fewer than
@@ -521,7 +677,9 @@
       // arrays as long as the initialization is trivial (e.g. if they
       // have a non-trivial destructor, but not a non-trivial constructor).
       if (D.getInit() &&
-          (Ty->isArrayType() || Ty->isRecordType()) && Ty->isPODType() &&
+          (Ty->isArrayType() || Ty->isRecordType()) && 
+          (Ty.isPODType(getContext()) ||
+           getContext().getBaseElementType(Ty)->isObjCObjectPointerType()) &&
           D.getInit()->isConstantInitializer(getContext(), false)) {
 
         // If the variable's a const type, and it's neither an NRVO
@@ -765,29 +923,30 @@
 /// \param capturedByInit true if the variable is a __block variable
 ///   whose address is potentially changed by the initializer
 void CodeGenFunction::EmitExprAsInit(const Expr *init,
-                                     const VarDecl *var,
+                                     const ValueDecl *D,
                                      llvm::Value *loc,
                                      CharUnits alignment,
                                      bool capturedByInit) {
-  QualType type = var->getType();
+  QualType type = D->getType();
   bool isVolatile = type.isVolatileQualified();
 
   if (type->isReferenceType()) {
-    RValue RV = EmitReferenceBindingToExpr(init, var);
-    if (capturedByInit) loc = BuildBlockByrefAddress(loc, var);
+    RValue RV = EmitReferenceBindingToExpr(init, D);
+    if (capturedByInit) 
+      loc = BuildBlockByrefAddress(loc, cast<VarDecl>(D));
     EmitStoreOfScalar(RV.getScalarVal(), loc, false,
                       alignment.getQuantity(), type);
   } else if (!hasAggregateLLVMType(type)) {
-    llvm::Value *V = EmitScalarExpr(init);
-    if (capturedByInit) loc = BuildBlockByrefAddress(loc, var);
-    EmitStoreOfScalar(V, loc, isVolatile, alignment.getQuantity(), type);
+    EmitScalarInit(init, D, loc, capturedByInit, isVolatile,
+                   alignment.getQuantity(), type);
   } else if (type->isAnyComplexType()) {
     ComplexPairTy complex = EmitComplexExpr(init);
-    if (capturedByInit) loc = BuildBlockByrefAddress(loc, var);
+    if (capturedByInit) loc = BuildBlockByrefAddress(loc, cast<VarDecl>(D));
     StoreComplexToAddr(complex, loc, isVolatile);
   } else {
     // TODO: how can we delay here if D is captured by its initializer?
-    EmitAggExpr(init, AggValueSlot::forAddr(loc, isVolatile, true, false));
+    EmitAggExpr(init, AggValueSlot::forAddr(loc, type.getQualifiers(), true, 
+                                            false));
   }
 }
 
@@ -799,7 +958,7 @@
 
   const VarDecl &D = *emission.Variable;
 
-  // Handle C++ destruction of variables.
+  // Handle C++ or ARC destruction of variables.
   if (getLangOptions().CPlusPlus) {
     QualType type = D.getType();
     QualType baseType = getContext().getBaseElementType(type);
@@ -830,6 +989,12 @@
     }
   }
 
+  if (Qualifiers::ObjCLifetime lifetime
+        = D.getType().getQualifiers().getObjCLifetime()) {
+    llvm::Value *loc = emission.getObjectAddress(*this);
+    EmitAutoVarWithLifetime(*this, D, loc, lifetime);
+  }
+
   // Handle the cleanup attribute.
   if (const CleanupAttr *CA = D.getAttr<CleanupAttr>()) {
     const FunctionDecl *FD = CA->getFunctionDecl();
@@ -847,6 +1012,22 @@
     enterByrefCleanup(emission);
 }
 
+namespace {
+  /// A cleanup to perform a release of an object at the end of a
+  /// function.  This is used to balance out the incoming +1 of a
+  /// ns_consumed argument when we can't reasonably do that just by
+  /// not doing the initial retain for a __block argument.
+  struct ConsumeARCParameter : EHScopeStack::Cleanup {
+    ConsumeARCParameter(llvm::Value *param) : Param(param) {}
+
+    llvm::Value *Param;
+
+    void Emit(CodeGenFunction &CGF, bool IsForEH) {
+      CGF.EmitARCRelease(Param, /*precise*/ false);
+    }
+  };
+}
+
 /// Emit an alloca (or GlobalValue depending on target)
 /// for the specified parameter and set up LocalDeclMap.
 void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
@@ -883,10 +1064,53 @@
     // Otherwise, create a temporary to hold the value.
     DeclPtr = CreateMemTemp(Ty, D.getName() + ".addr");
 
+    bool doStore = true;
+
+    Qualifiers qs = Ty.getQualifiers();
+
+    if (Qualifiers::ObjCLifetime lt = qs.getObjCLifetime()) {
+      // We honor __attribute__((ns_consumed)) for types with lifetime.
+      // For __strong, it's handled by just skipping the initial retain;
+      // otherwise we have to balance out the initial +1 with an extra
+      // cleanup to do the release at the end of the function.
+      bool isConsumed = D.hasAttr<NSConsumedAttr>();
+
+      // 'self' is always formally __strong, but if this is not an
+      // init method then we don't want to retain it.
+      if (lt == Qualifiers::OCL_Strong && qs.hasConst() &&
+          isa<ImplicitParamDecl>(D)) {
+        const ObjCMethodDecl *method = cast<ObjCMethodDecl>(CurCodeDecl);
+        assert(&D == method->getSelfDecl());
+        assert(method->getMethodFamily() != OMF_init);
+        lt = Qualifiers::OCL_ExplicitNone;
+      }
+
+      if (lt == Qualifiers::OCL_Strong) {
+        if (!isConsumed)
+          // Don't use objc_retainBlock for block pointers, because we
+          // don't want to Block_copy something just because we got it
+          // as a parameter.
+          Arg = EmitARCRetainNonBlock(Arg);
+      } else {
+        // Push the cleanup for a consumed parameter.
+        if (isConsumed)
+          EHStack.pushCleanup<ConsumeARCParameter>(getARCCleanupKind(), Arg);
+
+        if (lt == Qualifiers::OCL_Weak) {
+          EmitARCInitWeak(DeclPtr, Arg);
+          doStore = false; // The weak init is a store, no need to do two
+        }
+      }
+
+      // Enter the cleanup scope.
+      EmitAutoVarWithLifetime(*this, D, DeclPtr, lt);
+    }
+
     // Store the initial value into the alloca.
-    EmitStoreOfScalar(Arg, DeclPtr, Ty.isVolatileQualified(),
-                      getContext().getDeclAlign(&D).getQuantity(), Ty,
-                      CGM.getTBAAInfo(Ty));
+    if (doStore)
+      EmitStoreOfScalar(Arg, DeclPtr, Ty.isVolatileQualified(),
+                        getContext().getDeclAlign(&D).getQuantity(), Ty,
+                        CGM.getTBAAInfo(Ty));
   }
 
   llvm::Value *&DMEntry = LocalDeclMap[&D];

Modified: cfe/trunk/lib/CodeGen/CGDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDeclCXX.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDeclCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDeclCXX.cpp Wed Jun 15 18:02:42 2011
@@ -34,20 +34,22 @@
 
   unsigned Alignment = Context.getDeclAlign(&D).getQuantity();
   if (!CGF.hasAggregateLLVMType(T)) {
-    llvm::Value *V = CGF.EmitScalarExpr(Init);
     CodeGenModule &CGM = CGF.CGM;
     Qualifiers::GC GCAttr = CGM.getContext().getObjCGCAttrKind(T);
     if (GCAttr == Qualifiers::Strong)
-      CGM.getObjCRuntime().EmitObjCGlobalAssign(CGF, V, DeclPtr,
-                                                D.isThreadSpecified());
+      CGM.getObjCRuntime().EmitObjCGlobalAssign(CGF, CGF.EmitScalarExpr(Init),
+                                                DeclPtr, D.isThreadSpecified());
     else if (GCAttr == Qualifiers::Weak)
-      CGM.getObjCRuntime().EmitObjCWeakAssign(CGF, V, DeclPtr);
+        CGM.getObjCRuntime().EmitObjCWeakAssign(CGF, CGF.EmitScalarExpr(Init),
+                                                DeclPtr);
     else
-      CGF.EmitStoreOfScalar(V, DeclPtr, isVolatile, Alignment, T);
+      CGF.EmitScalarInit(Init, &D, DeclPtr, false, isVolatile, Alignment,
+                         D.getType());
   } else if (T->isAnyComplexType()) {
     CGF.EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile);
   } else {
-    CGF.EmitAggExpr(Init, AggValueSlot::forAddr(DeclPtr, isVolatile, true));
+    CGF.EmitAggExpr(Init, AggValueSlot::forAddr(DeclPtr, T.getQualifiers(),
+                                                true));
   }
 }
 
@@ -291,10 +293,21 @@
                 getTypes().getNullaryFunctionInfo(),
                 FunctionArgList(), SourceLocation());
 
+  RunCleanupsScope Scope(*this);
+
+  // When building in Objective-C++ ARC mode, create an autorelease pool
+  // around the global initializers.
+  if (getLangOptions().ObjCAutoRefCount && getLangOptions().CPlusPlus) {    
+    llvm::Value *token = EmitObjCAutoreleasePoolPush();
+    EmitObjCAutoreleasePoolCleanup(token);
+  }
+  
   for (unsigned i = 0; i != NumDecls; ++i)
     if (Decls[i])
-      Builder.CreateCall(Decls[i]);
+      Builder.CreateCall(Decls[i]);    
 
+  Scope.ForceCleanup();
+  
   FinishFunction();
 }
 

Modified: cfe/trunk/lib/CodeGen/CGException.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGException.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGException.cpp Wed Jun 15 18:02:42 2011
@@ -354,7 +354,8 @@
   // evaluated but before the exception is caught.  But the best way
   // to handle that is to teach EmitAggExpr to do the final copy
   // differently if it can't be elided.
-  CGF.EmitAnyExprToMem(e, typedAddr, /*Volatile*/ false, /*IsInit*/ true);
+  CGF.EmitAnyExprToMem(e, typedAddr, e->getType().getQualifiers(), 
+                       /*IsInit*/ true);
 
   // Deactivate the cleanup block.
   CGF.DeactivateCleanupBlock(cleanup);
@@ -1084,7 +1085,8 @@
   CGF.EHStack.pushTerminate();
 
   // Perform the copy construction.
-  CGF.EmitAggExpr(copyExpr, AggValueSlot::forAddr(ParamAddr, false, false));
+  CGF.EmitAggExpr(copyExpr, AggValueSlot::forAddr(ParamAddr, Qualifiers(), 
+                                                  false));
 
   // Leave the terminate scope.
   CGF.EHStack.popTerminate();

Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Wed Jun 15 18:02:42 2011
@@ -131,12 +131,12 @@
 /// location.
 void CodeGenFunction::EmitAnyExprToMem(const Expr *E,
                                        llvm::Value *Location,
-                                       bool IsLocationVolatile,
+                                       Qualifiers Quals,
                                        bool IsInit) {
   if (E->getType()->isAnyComplexType())
-    EmitComplexExprIntoAddr(E, Location, IsLocationVolatile);
+    EmitComplexExprIntoAddr(E, Location, Quals.hasVolatile());
   else if (hasAggregateLLVMType(E->getType()))
-    EmitAggExpr(E, AggValueSlot::forAddr(Location, IsLocationVolatile, IsInit));
+    EmitAggExpr(E, AggValueSlot::forAddr(Location, Quals, IsInit));
   else {
     RValue RV = RValue::get(EmitScalarExpr(E, /*Ignore*/ false));
     LValue LV = MakeAddrLValue(Location, E->getType());
@@ -203,7 +203,10 @@
 EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
                             llvm::Value *&ReferenceTemporary,
                             const CXXDestructorDecl *&ReferenceTemporaryDtor,
+                            QualType &ObjCARCReferenceLifetimeType,
                             const NamedDecl *InitializedDecl) {
+  ObjCARCReferenceLifetimeType = QualType();
+  
   if (const CXXDefaultArgExpr *DAE = dyn_cast<CXXDefaultArgExpr>(E))
     E = DAE->getExpr();
   
@@ -213,6 +216,7 @@
     return EmitExprForReferenceBinding(CGF, TE->getSubExpr(), 
                                        ReferenceTemporary, 
                                        ReferenceTemporaryDtor,
+                                       ObjCARCReferenceLifetimeType,
                                        InitializedDecl);
   }
 
@@ -279,12 +283,10 @@
         !E->getType()->isAnyComplexType()) {
       ReferenceTemporary = CreateReferenceTemporary(CGF, E->getType(), 
                                                     InitializedDecl);
-      AggSlot = AggValueSlot::forAddr(ReferenceTemporary, false,
+      AggSlot = AggValueSlot::forAddr(ReferenceTemporary, Qualifiers(),
                                       InitializedDecl != 0);
     }
-      
-    RV = CGF.EmitAnyExpr(E, AggSlot);
-
+    
     if (InitializedDecl) {
       // Get the destructor for the reference temporary.
       if (const RecordType *RT = E->getType()->getAs<RecordType>()) {
@@ -292,8 +294,37 @@
         if (!ClassDecl->hasTrivialDestructor())
           ReferenceTemporaryDtor = ClassDecl->getDestructor();
       }
+      else if (CGF.getContext().getLangOptions().ObjCAutoRefCount) {
+        if (const ValueDecl *InitVD = dyn_cast<ValueDecl>(InitializedDecl)) {
+          if (const ReferenceType *RefType
+                                  = InitVD->getType()->getAs<ReferenceType>()) {
+            QualType PointeeType = RefType->getPointeeType();
+            if (PointeeType->isObjCLifetimeType() &&
+                PointeeType.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) {
+              // Objective-C++ ARC: We're binding a reference to 
+              // lifetime-qualified type to a temporary, so we need to extend 
+              // the lifetime of the temporary with appropriate retain/release/
+              // autorelease calls.
+              ObjCARCReferenceLifetimeType = PointeeType;
+              
+              // Create a temporary variable that we can bind the reference to.
+              ReferenceTemporary = CreateReferenceTemporary(CGF, PointeeType, 
+                                                            InitializedDecl);
+
+              unsigned Alignment =
+                CGF.getContext().getTypeAlignInChars(PointeeType).getQuantity();
+              CGF.EmitScalarInit(E, InitVD, ReferenceTemporary, false,
+                                 PointeeType.isVolatileQualified(), 
+                                 Alignment, PointeeType);
+              return ReferenceTemporary;
+            }
+          }
+        }
+      }
     }
 
+    RV = CGF.EmitAnyExpr(E, AggSlot);
+
     // Check if need to perform derived-to-base casts and/or field accesses, to
     // get from the temporary object we created (and, potentially, for which we
     // extended the lifetime) to the subobject we're binding the reference to.
@@ -361,26 +392,60 @@
                                             const NamedDecl *InitializedDecl) {
   llvm::Value *ReferenceTemporary = 0;
   const CXXDestructorDecl *ReferenceTemporaryDtor = 0;
+  QualType ObjCARCReferenceLifetimeType;
   llvm::Value *Value = EmitExprForReferenceBinding(*this, E, ReferenceTemporary,
                                                    ReferenceTemporaryDtor,
+                                                   ObjCARCReferenceLifetimeType,
                                                    InitializedDecl);
-  if (!ReferenceTemporaryDtor)
+  if (!ReferenceTemporaryDtor && ObjCARCReferenceLifetimeType.isNull())
     return RValue::get(Value);
   
   // Make sure to call the destructor for the reference temporary.
-  if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(InitializedDecl)) {
-    if (VD->hasGlobalStorage()) {
+  const VarDecl *VD = dyn_cast_or_null<VarDecl>(InitializedDecl);
+  if (VD && VD->hasGlobalStorage()) {
+    if (ReferenceTemporaryDtor) {
       llvm::Constant *DtorFn = 
         CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete);
       EmitCXXGlobalDtorRegistration(DtorFn, 
                                     cast<llvm::Constant>(ReferenceTemporary));
-      
-      return RValue::get(Value);
+    } else {
+      assert(!ObjCARCReferenceLifetimeType.isNull());
+      // Note: We intentionally do not register a global "destructor" to
+      // release the object.
     }
+    
+    return RValue::get(Value);
   }
 
-  PushDestructorCleanup(ReferenceTemporaryDtor, ReferenceTemporary);
-
+  if (ReferenceTemporaryDtor)
+    PushDestructorCleanup(ReferenceTemporaryDtor, ReferenceTemporary);
+  else {
+    switch (ObjCARCReferenceLifetimeType.getObjCLifetime()) {
+    case Qualifiers::OCL_None:
+      llvm_unreachable("Not a reference temporary that needs to be deallocated");
+      break;
+        
+    case Qualifiers::OCL_ExplicitNone:
+    case Qualifiers::OCL_Autoreleasing:
+      // Nothing to do.
+      break;        
+        
+    case Qualifiers::OCL_Strong:
+      PushARCReleaseCleanup(getARCCleanupKind(), ObjCARCReferenceLifetimeType, 
+                            ReferenceTemporary,
+                            VD && VD->hasAttr<ObjCPreciseLifetimeAttr>());
+      break;
+        
+    case Qualifiers::OCL_Weak:
+      // __weak objects always get EH cleanups; otherwise, exceptions
+      // could cause really nasty crashes instead of mere leaks.
+      PushARCWeakReleaseCleanup(NormalAndEHCleanup, 
+                                ObjCARCReferenceLifetimeType, 
+                                ReferenceTemporary);
+      break;        
+    }
+  }
+  
   return RValue::get(Value);
 }
 
@@ -599,6 +664,7 @@
   case Expr::CXXDynamicCastExprClass:
   case Expr::CXXReinterpretCastExprClass:
   case Expr::CXXConstCastExprClass:
+  case Expr::ObjCBridgedCastExprClass:
     return EmitCastLValue(cast<CastExpr>(E));
   }
 }
@@ -668,6 +734,8 @@
     return RValue::get(CGM.getObjCRuntime().EmitObjCWeakRead(*this,
                                                              AddrWeakObj));
   }
+  if (LV.getQuals().getObjCLifetime() == Qualifiers::OCL_Weak)
+    return RValue::get(EmitARCLoadWeak(LV.getAddress()));
 
   if (LV.isSimple()) {
     llvm::Value *Ptr = LV.getAddress();
@@ -838,6 +906,31 @@
     return EmitStoreThroughPropertyRefLValue(Src, Dst);
   }
 
+  // There's special magic for assigning into an ARC-qualified l-value.
+  if (Qualifiers::ObjCLifetime Lifetime = Dst.getQuals().getObjCLifetime()) {
+    switch (Lifetime) {
+    case Qualifiers::OCL_None:
+      llvm_unreachable("present but none");
+
+    case Qualifiers::OCL_ExplicitNone:
+      // nothing special
+      break;
+
+    case Qualifiers::OCL_Strong:
+      EmitARCStoreStrong(Dst, Ty, Src.getScalarVal(), /*ignore*/ true);
+      return;
+
+    case Qualifiers::OCL_Weak:
+      EmitARCStoreWeak(Dst.getAddress(), Src.getScalarVal(), /*ignore*/ true);
+      return;
+
+    case Qualifiers::OCL_Autoreleasing:
+      Src = RValue::get(EmitObjCExtendObjectLifetime(Ty, Src.getScalarVal()));
+      // fall into the normal path
+      break;
+    }
+  }
+
   if (Dst.isObjCWeak() && !Dst.isNonGC()) {
     // load of a __weak object.
     llvm::Value *LvalueDst = Dst.getAddress();
@@ -1113,7 +1206,12 @@
     setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV);
     return;
   }
-  
+
+  if (const ObjCBridgedCastExpr *Exp = dyn_cast<ObjCBridgedCastExpr>(E)) {
+    setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV);
+    return;
+  }
+
   if (const ArraySubscriptExpr *Exp = dyn_cast<ArraySubscriptExpr>(E)) {
     setObjCGCLValueClass(Ctx, Exp->getBase(), LV);
     if (LV.isObjCIvar() && !LV.isObjCArray()) 
@@ -1734,7 +1832,8 @@
   const Expr *InitExpr = E->getInitializer();
   LValue Result = MakeAddrLValue(DeclPtr, E->getType());
 
-  EmitAnyExprToMem(InitExpr, DeclPtr, /*Volatile*/ false, /*Init*/ true);
+  EmitAnyExprToMem(InitExpr, DeclPtr, E->getType().getQualifiers(),
+                   /*Init*/ true);
 
   return Result;
 }
@@ -1863,13 +1962,15 @@
   case CK_DerivedToBaseMemberPointer:
   case CK_BaseToDerivedMemberPointer:
   case CK_MemberPointerToBoolean:
-  case CK_AnyPointerToBlockPointerCast: {
+  case CK_AnyPointerToBlockPointerCast:
+  case CK_ObjCProduceObject:
+  case CK_ObjCConsumeObject: {
     // These casts only produce lvalues when we're binding a reference to a 
     // temporary realized from a (converted) pure rvalue. Emit the expression
     // as a value, copy it into a temporary, and return an lvalue referring to
     // that temporary.
     llvm::Value *V = CreateMemTemp(E->getType(), "ref.temp");
-    EmitAnyExprToMem(E, V, false, false);
+    EmitAnyExprToMem(E, V, E->getType().getQualifiers(), false);
     return MakeAddrLValue(V, E->getType());
   }
 
@@ -1988,13 +2089,60 @@
     if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(TargetDecl))
       return EmitCXXOperatorMemberCallExpr(CE, MD, ReturnValue);
 
-  if (isa<CXXPseudoDestructorExpr>(E->getCallee()->IgnoreParens())) {
-    // C++ [expr.pseudo]p1:
-    //   The result shall only be used as the operand for the function call
-    //   operator (), and the result of such a call has type void. The only
-    //   effect is the evaluation of the postfix-expression before the dot or
-    //   arrow.
-    EmitScalarExpr(E->getCallee());
+  if (const CXXPseudoDestructorExpr *PseudoDtor 
+          = dyn_cast<CXXPseudoDestructorExpr>(E->getCallee()->IgnoreParens())) {
+    QualType DestroyedType = PseudoDtor->getDestroyedType();
+    if (getContext().getLangOptions().ObjCAutoRefCount &&
+        DestroyedType->isObjCLifetimeType() &&
+        (DestroyedType.getObjCLifetime() == Qualifiers::OCL_Strong ||
+         DestroyedType.getObjCLifetime() == Qualifiers::OCL_Weak)) {
+          // Automatic Reference Counting:
+          //   If the pseudo-expression names a retainable object with weak or strong
+          //   lifetime, the object shall be released.
+      bool isNonGC = false;
+      Expr *BaseExpr = PseudoDtor->getBase();
+      llvm::Value *BaseValue = NULL;
+      Qualifiers BaseQuals;
+      
+      // If this is s.x, emit s as an lvalue.  If it is s->x, emit s as a scalar.
+      if (PseudoDtor->isArrow()) {
+        BaseValue = EmitScalarExpr(BaseExpr);
+        const PointerType *PTy = BaseExpr->getType()->getAs<PointerType>();
+        BaseQuals = PTy->getPointeeType().getQualifiers();
+      } else {
+        LValue BaseLV = EmitLValue(BaseExpr);
+        if (BaseLV.isNonGC())
+          isNonGC = true;
+        BaseValue = BaseLV.getAddress();
+        QualType BaseTy = BaseExpr->getType();
+        BaseQuals = BaseTy.getQualifiers();
+      }
+          
+      switch (PseudoDtor->getDestroyedType().getObjCLifetime()) {
+      case Qualifiers::OCL_None:
+      case Qualifiers::OCL_ExplicitNone:
+      case Qualifiers::OCL_Autoreleasing:
+        break;
+        
+      case Qualifiers::OCL_Strong:
+        EmitARCRelease(Builder.CreateLoad(BaseValue, 
+                          PseudoDtor->getDestroyedType().isVolatileQualified()), 
+                       /*precise*/ true);
+        break;
+
+      case Qualifiers::OCL_Weak:
+        EmitARCDestroyWeak(BaseValue);
+        break;
+      }
+    } else {
+      // C++ [expr.pseudo]p1:
+      //   The result shall only be used as the operand for the function call
+      //   operator (), and the result of such a call has type void. The only
+      //   effect is the evaluation of the postfix-expression before the dot or
+      //   arrow.      
+      EmitScalarExpr(E->getCallee());
+    }
+    
     return RValue::get(0);
   }
 
@@ -2016,9 +2164,25 @@
     return EmitPointerToDataMemberBinaryExpr(E);
 
   assert(E->getOpcode() == BO_Assign && "unexpected binary l-value");
+
+  // Note that in all of these cases, __block variables need the RHS
+  // evaluated first just in case the variable gets moved by the RHS.
   
   if (!hasAggregateLLVMType(E->getType())) {
-    // __block variables need the RHS evaluated first.
+    switch (E->getLHS()->getType().getObjCLifetime()) {
+    case Qualifiers::OCL_Strong:
+      return EmitARCStoreStrong(E, /*ignored*/ false).first;
+
+    case Qualifiers::OCL_Autoreleasing:
+      return EmitARCStoreAutoreleasing(E).first;
+
+    // No reason to do any of these differently.
+    case Qualifiers::OCL_None:
+    case Qualifiers::OCL_ExplicitNone:
+    case Qualifiers::OCL_Weak:
+      break;
+    }
+
     RValue RV = EmitAnyExpr(E->getRHS());
     LValue LV = EmitLValue(E->getLHS());
     EmitStoreThroughLValue(RV, LV, E->getType());

Modified: cfe/trunk/lib/CodeGen/CGExprAgg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprAgg.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprAgg.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprAgg.cpp Wed Jun 15 18:02:42 2011
@@ -339,6 +339,8 @@
   case CK_IntegralComplexToBoolean:
   case CK_IntegralComplexCast:
   case CK_IntegralComplexToFloatingComplex:
+  case CK_ObjCProduceObject:
+  case CK_ObjCConsumeObject:
     llvm_unreachable("cast kind invalid for aggregate types");
   }
 }
@@ -570,8 +572,13 @@
   } else if (T->isAnyComplexType()) {
     CGF.EmitComplexExprIntoAddr(E, LV.getAddress(), false);
   } else if (CGF.hasAggregateLLVMType(T)) {
-    CGF.EmitAggExpr(E, AggValueSlot::forAddr(LV.getAddress(), false, true,
+    CGF.EmitAggExpr(E, AggValueSlot::forAddr(LV.getAddress(), 
+                                             T.getQualifiers(), true,
                                              false, Dest.isZeroed()));
+  } else if (LV.isSimple()) {
+    CGF.EmitScalarInit(E, /*D=*/0, LV.getAddress(), /*Captured=*/false, 
+                       LV.isVolatileQualified(), LV.getAlignment(),
+                       T);
   } else {
     CGF.EmitStoreThroughLValue(RValue::get(CGF.EmitScalarExpr(E)), LV, T);
   }
@@ -636,6 +643,8 @@
     uint64_t NumArrayElements = AType->getNumElements();
     QualType ElementType = CGF.getContext().getCanonicalType(E->getType());
     ElementType = CGF.getContext().getAsArrayType(ElementType)->getElementType();
+    ElementType = CGF.getContext().getQualifiedType(ElementType, 
+                                                    Dest.getQualifiers());
 
     bool hasNonTrivialCXXConstructor = false;
     if (CGF.getContext().getLangOptions().CPlusPlus)
@@ -645,8 +654,6 @@
         hasNonTrivialCXXConstructor = !RD->hasTrivialDefaultConstructor();
       }
 
-    // FIXME: were we intentionally ignoring address spaces and GC attributes?
-
     for (uint64_t i = 0; i != NumArrayElements; ++i) {
       // If we're done emitting initializers and the destination is known-zeroed
       // then we're done.
@@ -873,8 +880,6 @@
 ///
 /// \param IsInitializer - true if this evaluation is initializing an
 /// object whose lifetime is already being managed.
-//
-// FIXME: Take Qualifiers object.
 void CodeGenFunction::EmitAggExpr(const Expr *E, AggValueSlot Slot,
                                   bool IgnoreResult) {
   assert(E && hasAggregateLLVMType(E->getType()) &&
@@ -892,7 +897,7 @@
   assert(hasAggregateLLVMType(E->getType()) && "Invalid argument!");
   llvm::Value *Temp = CreateMemTemp(E->getType());
   LValue LV = MakeAddrLValue(Temp, E->getType());
-  EmitAggExpr(E, AggValueSlot::forAddr(Temp, LV.isVolatileQualified(), false));
+  EmitAggExpr(E, AggValueSlot::forLValue(LV, false));
   return LV;
 }
 
@@ -954,7 +959,10 @@
     llvm::Type::getInt8PtrTy(getLLVMContext(), SPT->getAddressSpace());
   SrcPtr = Builder.CreateBitCast(SrcPtr, SBP, "tmp");
 
-  if (const RecordType *RecordTy = Ty->getAs<RecordType>()) {
+  // Don't do any of the memmove_collectable tests if GC isn't set.
+  if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC) {
+    // fall through
+  } else if (const RecordType *RecordTy = Ty->getAs<RecordType>()) {
     RecordDecl *Record = RecordTy->getDecl();
     if (Record->hasObjectMember()) {
       CharUnits size = TypeInfo.first;
@@ -964,7 +972,7 @@
                                                     SizeVal);
       return;
     }
-  } else if (getContext().getAsArrayType(Ty)) {
+  } else if (Ty->isArrayType()) {
     QualType BaseType = getContext().getBaseElementType(Ty);
     if (const RecordType *RecordTy = BaseType->getAs<RecordType>()) {
       if (RecordTy->getDecl()->hasObjectMember()) {

Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Wed Jun 15 18:02:42 2011
@@ -708,15 +708,14 @@
   unsigned Alignment =
     CGF.getContext().getTypeAlignInChars(AllocType).getQuantity();
   if (!CGF.hasAggregateLLVMType(AllocType)) 
-    CGF.EmitStoreOfScalar(CGF.EmitScalarExpr(Init), NewPtr,
-                          AllocType.isVolatileQualified(), Alignment,
-                          AllocType);
+    CGF.EmitScalarInit(Init, 0, NewPtr, false, AllocType.isVolatileQualified(),
+                       Alignment, AllocType);
   else if (AllocType->isAnyComplexType())
     CGF.EmitComplexExprIntoAddr(Init, NewPtr, 
                                 AllocType.isVolatileQualified());
   else {
     AggValueSlot Slot
-      = AggValueSlot::forAddr(NewPtr, AllocType.isVolatileQualified(), true);
+      = AggValueSlot::forAddr(NewPtr, AllocType.getQualifiers(), true);
     CGF.EmitAggExpr(Init, Slot);
   }
 }
@@ -1075,7 +1074,7 @@
   // CXXNewExpr::shouldNullCheckAllocation()) and we have an
   // interesting initializer.
   bool nullCheck = allocatorType->isNothrow(getContext()) &&
-    !(allocType->isPODType() && !E->hasInitializer());
+    !(allocType.isPODType(getContext()) && !E->hasInitializer());
 
   llvm::BasicBlock *nullCheckBB = 0;
   llvm::BasicBlock *contBB = 0;
@@ -1247,7 +1246,29 @@
   if (Dtor)
     CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
                               /*ForVirtualBase=*/false, Ptr);
+  else if (CGF.getLangOptions().ObjCAutoRefCount &&
+           ElementType->isObjCLifetimeType()) {
+    switch (ElementType.getObjCLifetime()) {
+    case Qualifiers::OCL_None:
+    case Qualifiers::OCL_ExplicitNone:
+    case Qualifiers::OCL_Autoreleasing:
+      break;
 
+    case Qualifiers::OCL_Strong: {
+      // Load the pointer value.
+      llvm::Value *PtrValue = CGF.Builder.CreateLoad(Ptr, 
+                                             ElementType.isVolatileQualified());
+        
+      CGF.EmitARCRelease(PtrValue, /*precise*/ true);
+      break;
+    }
+        
+    case Qualifiers::OCL_Weak:
+      CGF.EmitARCDestroyWeak(Ptr);
+      break;
+    }
+  }
+           
   CGF.PopCleanupBlock();
 }
 
@@ -1339,6 +1360,65 @@
                             " for a class with destructor");
       CGF.EmitCXXAggrDestructorCall(RD->getDestructor(), NumElements, Ptr);
     }
+  } else if (CGF.getLangOptions().ObjCAutoRefCount &&
+             ElementType->isObjCLifetimeType() &&
+             (ElementType.getObjCLifetime() == Qualifiers::OCL_Strong ||
+              ElementType.getObjCLifetime() == Qualifiers::OCL_Weak)) {
+    bool IsStrong = ElementType.getObjCLifetime() == Qualifiers::OCL_Strong;
+    const llvm::Type *SizeLTy = CGF.ConvertType(CGF.getContext().getSizeType());
+    llvm::Value *One = llvm::ConstantInt::get(SizeLTy, 1);
+    
+    // Create a temporary for the loop index and initialize it with count of
+    // array elements.
+    llvm::Value *IndexPtr = CGF.CreateTempAlloca(SizeLTy, "loop.index");
+    
+    // Store the number of elements in the index pointer.
+    CGF.Builder.CreateStore(NumElements, IndexPtr);
+    
+    // Start the loop with a block that tests the condition.
+    llvm::BasicBlock *CondBlock = CGF.createBasicBlock("for.cond");
+    llvm::BasicBlock *AfterFor = CGF.createBasicBlock("for.end");
+    
+    CGF.EmitBlock(CondBlock);
+    
+    llvm::BasicBlock *ForBody = CGF.createBasicBlock("for.body");
+    
+    // Generate: if (loop-index != 0 fall to the loop body,
+    // otherwise, go to the block after the for-loop.
+    llvm::Value* zeroConstant = llvm::Constant::getNullValue(SizeLTy);
+    llvm::Value *Counter = CGF.Builder.CreateLoad(IndexPtr);
+    llvm::Value *IsNE = CGF.Builder.CreateICmpNE(Counter, zeroConstant,
+                                                 "isne");
+    // If the condition is true, execute the body.
+    CGF.Builder.CreateCondBr(IsNE, ForBody, AfterFor);
+    
+    CGF.EmitBlock(ForBody);
+    
+    llvm::BasicBlock *ContinueBlock = CGF.createBasicBlock("for.inc");
+    // Inside the loop body, emit the constructor call on the array element.
+    Counter = CGF.Builder.CreateLoad(IndexPtr);
+    Counter = CGF.Builder.CreateSub(Counter, One);
+    llvm::Value *Address = CGF.Builder.CreateInBoundsGEP(Ptr, Counter, 
+                                                         "arrayidx");
+    if (IsStrong)
+      CGF.EmitARCRelease(CGF.Builder.CreateLoad(Address, 
+                                          ElementType.isVolatileQualified()),
+                         /*precise*/ true);
+    else
+      CGF.EmitARCDestroyWeak(Address);
+    
+    CGF.EmitBlock(ContinueBlock);
+    
+    // Emit the decrement of the loop counter.
+    Counter = CGF.Builder.CreateLoad(IndexPtr);
+    Counter = CGF.Builder.CreateSub(Counter, One, "dec");
+    CGF.Builder.CreateStore(Counter, IndexPtr);
+    
+    // Finally, branch back up to the condition for the next iteration.
+    CGF.EmitBranch(CondBlock);
+    
+    // Emit the fall-through block.
+    CGF.EmitBlock(AfterFor, true);    
   }
 
   CGF.PopCleanupBlock();

Modified: cfe/trunk/lib/CodeGen/CGExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprConstant.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Wed Jun 15 18:02:42 2011
@@ -570,6 +570,8 @@
     case CK_GetObjCProperty:
     case CK_ToVoid:
     case CK_Dynamic:
+    case CK_ObjCProduceObject:
+    case CK_ObjCConsumeObject:
       return 0;
 
     // These might need to be supported for constexpr.

Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Wed Jun 15 18:02:42 2011
@@ -1106,7 +1106,12 @@
     // function pointers on Itanium and ARM).
     return CGF.CGM.getCXXABI().EmitMemberPointerConversion(CGF, CE, Src);
   }
-  
+
+  case CK_ObjCProduceObject:
+    return CGF.EmitARCRetainScalarExpr(E);
+  case CK_ObjCConsumeObject:
+    return CGF.EmitObjCConsumeObject(E->getType(), Visit(E));
+
   case CK_FloatingRealToComplex:
   case CK_FloatingComplexCast:
   case CK_IntegralRealToComplex:
@@ -2228,20 +2233,42 @@
 Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
   bool Ignore = TestAndClearIgnoreResultAssign();
 
-  // __block variables need to have the rhs evaluated first, plus this should
-  // improve codegen just a little.
-  Value *RHS = Visit(E->getRHS());
-  LValue LHS = EmitCheckedLValue(E->getLHS());
-
-  // Store the value into the LHS.  Bit-fields are handled specially
-  // because the result is altered by the store, i.e., [C99 6.5.16p1]
-  // 'An assignment expression has the value of the left operand after
-  // the assignment...'.
-  if (LHS.isBitField())
-    CGF.EmitStoreThroughBitfieldLValue(RValue::get(RHS), LHS, E->getType(),
-                                       &RHS);
-  else
-    CGF.EmitStoreThroughLValue(RValue::get(RHS), LHS, E->getType());
+  Value *RHS;
+  LValue LHS;
+
+  switch (E->getLHS()->getType().getObjCLifetime()) {
+  case Qualifiers::OCL_Strong:
+    llvm::tie(LHS, RHS) = CGF.EmitARCStoreStrong(E, Ignore);
+    break;
+
+  case Qualifiers::OCL_Autoreleasing:
+    llvm::tie(LHS,RHS) = CGF.EmitARCStoreAutoreleasing(E);
+    break;
+
+  case Qualifiers::OCL_Weak:
+    RHS = Visit(E->getRHS());
+    LHS = EmitCheckedLValue(E->getLHS());    
+    RHS = CGF.EmitARCStoreWeak(LHS.getAddress(), RHS, Ignore);
+    break;
+
+  // No reason to do any of these differently.
+  case Qualifiers::OCL_None:
+  case Qualifiers::OCL_ExplicitNone:
+    // __block variables need to have the rhs evaluated first, plus
+    // this should improve codegen just a little.
+    RHS = Visit(E->getRHS());
+    LHS = EmitCheckedLValue(E->getLHS());
+
+    // Store the value into the LHS.  Bit-fields are handled specially
+    // because the result is altered by the store, i.e., [C99 6.5.16p1]
+    // 'An assignment expression has the value of the left operand after
+    // the assignment...'.
+    if (LHS.isBitField())
+      CGF.EmitStoreThroughBitfieldLValue(RValue::get(RHS), LHS, E->getType(),
+                                         &RHS);
+    else
+      CGF.EmitStoreThroughLValue(RValue::get(RHS), LHS, E->getType());
+  }
 
   // If the result is clearly ignored, return now.
   if (Ignore)

Modified: cfe/trunk/lib/CodeGen/CGObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjC.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjC.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjC.cpp Wed Jun 15 18:02:42 2011
@@ -15,15 +15,29 @@
 #include "CGObjCRuntime.h"
 #include "CodeGenFunction.h"
 #include "CodeGenModule.h"
+#include "TargetInfo.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/StmtObjC.h"
 #include "clang/Basic/Diagnostic.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/Target/TargetData.h"
+#include "llvm/InlineAsm.h"
 using namespace clang;
 using namespace CodeGen;
 
+typedef llvm::PointerIntPair<llvm::Value*,1,bool> TryEmitResult;
+static TryEmitResult
+tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e);
+
+/// Given the address of a variable of pointer type, find the correct
+/// null to store into it.
+static llvm::Constant *getNullForVariable(llvm::Value *addr) {
+  const llvm::Type *type =
+    cast<llvm::PointerType>(addr->getType())->getElementType();
+  return llvm::ConstantPointerNull::get(cast<llvm::PointerType>(type));
+}
+
 /// Emits an instance of NSConstantString representing the object.
 llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E)
 {
@@ -55,6 +69,7 @@
                                       RValue Result) {
   if (!Method)
     return Result;
+
   if (!Method->hasRelatedResultType() ||
       CGF.getContext().hasSameType(E->getType(), Method->getResultType()) ||
       !Result.isScalar())
@@ -71,6 +86,18 @@
   // implementation vary between runtimes.  We can get the receiver and
   // arguments in generic code.
 
+  bool isDelegateInit = E->isDelegateInitCall();
+
+  // We don't retain the receiver in delegate init calls, and this is
+  // safe because the receiver value is always loaded from 'self',
+  // which we zero out.  We don't want to Block_copy block receivers,
+  // though.
+  bool retainSelf =
+    (!isDelegateInit &&
+     CGM.getLangOptions().ObjCAutoRefCount &&
+     E->getMethodDecl() &&
+     E->getMethodDecl()->hasAttr<NSConsumesSelfAttr>());
+
   CGObjCRuntime &Runtime = CGM.getObjCRuntime();
   bool isSuperMessage = false;
   bool isClassMessage = false;
@@ -80,8 +107,15 @@
   llvm::Value *Receiver = 0;
   switch (E->getReceiverKind()) {
   case ObjCMessageExpr::Instance:
-    Receiver = EmitScalarExpr(E->getInstanceReceiver());
     ReceiverType = E->getInstanceReceiver()->getType();
+    if (retainSelf) {
+      TryEmitResult ter = tryEmitARCRetainScalarExpr(*this,
+                                                   E->getInstanceReceiver());
+      Receiver = ter.getPointer();
+      if (!ter.getInt())
+        Receiver = EmitARCRetainNonBlock(Receiver);
+    } else
+      Receiver = EmitScalarExpr(E->getInstanceReceiver());
     break;
 
   case ObjCMessageExpr::Class: {
@@ -92,6 +126,9 @@
     assert(OID && "Invalid Objective-C class message send");
     Receiver = Runtime.GetClass(Builder, OID);
     isClassMessage = true;
+
+    if (retainSelf)
+      Receiver = EmitARCRetainNonBlock(Receiver);
     break;
   }
 
@@ -99,6 +136,9 @@
     ReceiverType = E->getSuperType();
     Receiver = LoadObjCSelf();
     isSuperMessage = true;
+
+    if (retainSelf)
+      Receiver = EmitARCRetainNonBlock(Receiver);
     break;
 
   case ObjCMessageExpr::SuperClass:
@@ -106,14 +146,36 @@
     Receiver = LoadObjCSelf();
     isSuperMessage = true;
     isClassMessage = true;
+
+    if (retainSelf)
+      Receiver = EmitARCRetainNonBlock(Receiver);
     break;
   }
 
+  QualType ResultType =
+    E->getMethodDecl() ? E->getMethodDecl()->getResultType() : E->getType();
+
   CallArgList Args;
   EmitCallArgs(Args, E->getMethodDecl(), E->arg_begin(), E->arg_end());
 
-  QualType ResultType =
-    E->getMethodDecl() ? E->getMethodDecl()->getResultType() : E->getType();
+  // For delegate init calls in ARC, do an unsafe store of null into
+  // self.  This represents the call taking direct ownership of that
+  // value.  We have to do this after emitting the other call
+  // arguments because they might also reference self, but we don't
+  // have to worry about any of them modifying self because that would
+  // be an undefined read and write of an object in unordered
+  // expressions.
+  if (isDelegateInit) {
+    assert(getLangOptions().ObjCAutoRefCount &&
+           "delegate init calls should only be marked in ARC");
+
+    // Do an unsafe store of null into self.
+    llvm::Value *selfAddr =
+      LocalDeclMap[cast<ObjCMethodDecl>(CurCodeDecl)->getSelfDecl()];
+    assert(selfAddr && "no self entry for a delegate init call?");
+
+    Builder.CreateStore(getNullForVariable(selfAddr), selfAddr);
+  }
 
   RValue result;
   if (isSuperMessage) {
@@ -134,10 +196,52 @@
                                          Receiver, Args, OID,
                                          E->getMethodDecl());
   }
-  
+
+  // For delegate init calls in ARC, implicitly store the result of
+  // the call back into self.  This takes ownership of the value.
+  if (isDelegateInit) {
+    llvm::Value *selfAddr =
+      LocalDeclMap[cast<ObjCMethodDecl>(CurCodeDecl)->getSelfDecl()];
+    llvm::Value *newSelf = result.getScalarVal();
+
+    // The delegate return type isn't necessarily a matching type; in
+    // fact, it's quite likely to be 'id'.
+    const llvm::Type *selfTy =
+      cast<llvm::PointerType>(selfAddr->getType())->getElementType();
+    newSelf = Builder.CreateBitCast(newSelf, selfTy);
+
+    Builder.CreateStore(newSelf, selfAddr);
+  }
+
   return AdjustRelatedResultType(*this, E, E->getMethodDecl(), result);
 }
 
+namespace {
+struct FinishARCDealloc : EHScopeStack::Cleanup {
+  void Emit(CodeGenFunction &CGF, bool isForEH) {
+    const ObjCMethodDecl *method = cast<ObjCMethodDecl>(CGF.CurCodeDecl);
+    const ObjCImplementationDecl *impl
+      = cast<ObjCImplementationDecl>(method->getDeclContext());
+    const ObjCInterfaceDecl *iface = impl->getClassInterface();
+    if (!iface->getSuperClass()) return;
+
+    // Call [super dealloc] if we have a superclass.
+    llvm::Value *self = CGF.LoadObjCSelf();
+
+    CallArgList args;
+    CGF.CGM.getObjCRuntime().GenerateMessageSendSuper(CGF, ReturnValueSlot(),
+                                                      CGF.getContext().VoidTy,
+                                                      method->getSelector(),
+                                                      iface,
+                                                      /*is category*/ false,
+                                                      self,
+                                                      /*is class msg*/ false,
+                                                      args,
+                                                      method);
+  }
+};
+}
+
 /// StartObjCMethod - Begin emission of an ObjCMethod. This generates
 /// the LLVM function and sets the other context used by
 /// CodeGenFunction.
@@ -164,8 +268,21 @@
   CurGD = OMD;
 
   StartFunction(OMD, OMD->getResultType(), Fn, FI, args, StartLoc);
+
+  // In ARC, certain methods get an extra cleanup.
+  if (CGM.getLangOptions().ObjCAutoRefCount &&
+      OMD->isInstanceMethod() &&
+      OMD->getSelector().isUnarySelector()) {
+    const IdentifierInfo *ident = 
+      OMD->getSelector().getIdentifierInfoForSlot(0);
+    if (ident->isStr("dealloc"))
+      EHStack.pushCleanup<FinishARCDealloc>(getARCCleanupKind());
+  }
 }
 
+static llvm::Value *emitARCRetainLoadOfScalar(CodeGenFunction &CGF,
+                                              LValue lvalue, QualType type);
+
 void CodeGenFunction::GenerateObjCGetterBody(ObjCIvarDecl *Ivar, 
                                              bool IsAtomic, bool IsStrong) {
   LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), 
@@ -269,6 +386,9 @@
     RV = RValue::get(Builder.CreateBitCast(RV.getScalarVal(),
                                            Types.ConvertType(PD->getType())));
     EmitReturnOfRValue(RV, PD->getType());
+
+    // objc_getProperty does an autorelease, so we should suppress ours.
+    AutoreleaseResult = false;
   } else {
     const llvm::Triple &Triple = getContext().Target.getTriple();
     QualType IVART = Ivar->getType();
@@ -347,17 +467,23 @@
     else {
         LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), 
                                     Ivar, 0);
-        if (PD->getType()->isReferenceType()) {
-          RValue RV = RValue::get(LV.getAddress());
-          EmitReturnOfRValue(RV, PD->getType());
-        }
-        else {
-          CodeGenTypes &Types = CGM.getTypes();
-          RValue RV = EmitLoadOfLValue(LV, IVART);
-          RV = RValue::get(Builder.CreateBitCast(RV.getScalarVal(),
-                                               Types.ConvertType(PD->getType())));
-          EmitReturnOfRValue(RV, PD->getType());
+        QualType propType = PD->getType();
+
+        llvm::Value *value;
+        if (propType->isReferenceType()) {
+          value = LV.getAddress();
+        } else {
+          // In ARC, we want to emit this retained.
+          if (getLangOptions().ObjCAutoRefCount &&
+              PD->getType()->isObjCRetainableType())
+            value = emitARCRetainLoadOfScalar(*this, LV, IVART);
+          else
+            value = EmitLoadOfLValue(LV, IVART).getScalarVal();
+
+          value = Builder.CreateBitCast(value, ConvertType(propType));
         }
+
+        EmitReturnOfRValue(RValue::get(value), propType);
     }
   }
 
@@ -597,6 +723,11 @@
   };
 }
 
+static void pushReleaseForIvar(CodeGenFunction &CGF, ObjCIvarDecl *ivar,
+                               llvm::Value *self);
+static void pushWeakReleaseForIvar(CodeGenFunction &CGF, ObjCIvarDecl *ivar,
+                                   llvm::Value *self);
+
 static void emitCXXDestructMethod(CodeGenFunction &CGF,
                                   ObjCImplementationDecl *impl) {
   CodeGenFunction::RunCleanupsScope scope(CGF);
@@ -631,6 +762,14 @@
         CGF.EHStack.pushCleanup<CallIvarDtor>(NormalAndEHCleanup,
                                               ivar, self);
       break;
+
+    case QualType::DK_objc_strong_lifetime:
+      pushReleaseForIvar(CGF, ivar, self);
+      break;
+
+    case QualType::DK_objc_weak_lifetime:
+      pushWeakReleaseForIvar(CGF, ivar, self);
+      break;
     }
   }
 
@@ -645,6 +784,9 @@
 
   // Emit .cxx_construct.
   if (ctor) {
+    // Suppress the final autorelease in ARC.
+    AutoreleaseResult = false;
+
     llvm::SmallVector<CXXCtorInitializer *, 8> IvarInitializers;
     for (ObjCImplementationDecl::init_const_iterator B = IMP->init_begin(),
            E = IMP->init_end(); B != E; ++B) {
@@ -747,6 +889,16 @@
 
   llvm::Value *Receiver = LV.getPropertyRefBaseAddr();
 
+  if (CGM.getLangOptions().ObjCAutoRefCount) {
+    QualType receiverType;
+    if (E->isSuperReceiver())
+      receiverType = E->getSuperReceiverType();
+    else if (E->isClassReceiver())
+      receiverType = getContext().getObjCClassType();
+    else
+      receiverType = E->getBase()->getType();
+  }
+
   // Accesses to 'super' follow a different code path.
   if (E->isSuperReceiver())
     return AdjustRelatedResultType(*this, E, method,
@@ -757,9 +909,9 @@
   const ObjCInterfaceDecl *ReceiverClass
     = (E->isClassReceiver() ? E->getClassReceiver() : 0);
   return AdjustRelatedResultType(*this, E, method,
-                                 CGM.getObjCRuntime().
-                 GenerateMessageSend(*this, Return, ResultType, S,
-                                     Receiver, CallArgList(), ReceiverClass));
+          CGM.getObjCRuntime().
+             GenerateMessageSend(*this, Return, ResultType, S,
+                                 Receiver, CallArgList(), ReceiverClass));
 }
 
 void CodeGenFunction::EmitStoreThroughPropertyRefLValue(RValue Src,
@@ -1072,4 +1224,1197 @@
   CGM.getObjCRuntime().EmitSynchronizedStmt(*this, S);
 }
 
+/// Produce the code for a CK_ObjCProduceObject.  Just does a
+/// primitive retain.
+llvm::Value *CodeGenFunction::EmitObjCProduceObject(QualType type,
+                                                    llvm::Value *value) {
+  return EmitARCRetain(type, value);
+}
+
+namespace {
+  struct CallObjCRelease : EHScopeStack::Cleanup {
+    CallObjCRelease(QualType type, llvm::Value *ptr, llvm::Value *condition)
+      : type(type), ptr(ptr), condition(condition) {}
+    QualType type;
+    llvm::Value *ptr;
+    llvm::Value *condition;
+
+    void Emit(CodeGenFunction &CGF, bool forEH) {
+      llvm::Value *object;
+
+      // If we're in a conditional branch, we had to stash away in an
+      // alloca the pointer to be released.
+      llvm::BasicBlock *cont = 0;
+      if (condition) {
+        llvm::BasicBlock *release = CGF.createBasicBlock("release.yes");
+        cont = CGF.createBasicBlock("release.cont");
+
+        llvm::Value *cond = CGF.Builder.CreateLoad(condition);
+        CGF.Builder.CreateCondBr(cond, release, cont);
+        CGF.EmitBlock(release);
+        object = CGF.Builder.CreateLoad(ptr);
+      } else {
+        object = ptr;
+      }
+
+      CGF.EmitARCRelease(object, /*precise*/ true);
+
+      if (cont) CGF.EmitBlock(cont);
+    }
+  };
+}
+
+/// Produce the code for a CK_ObjCConsumeObject.  Does a primitive
+/// release at the end of the full-expression.
+llvm::Value *CodeGenFunction::EmitObjCConsumeObject(QualType type,
+                                                    llvm::Value *object) {
+  // If we're in a conditional branch, we need to make the cleanup
+  // conditional.  FIXME: this really needs to be supported by the
+  // environment.
+  llvm::AllocaInst *cond;
+  llvm::Value *ptr;
+  if (isInConditionalBranch()) {
+    cond = CreateTempAlloca(Builder.getInt1Ty(), "release.cond");
+    ptr = CreateTempAlloca(object->getType(), "release.value");
+
+    // The alloca is false until we get here.
+    // FIXME: er. doesn't this need to be set at the start of the condition?
+    InitTempAlloca(cond, Builder.getFalse());
+
+    // Then it turns true.
+    Builder.CreateStore(Builder.getTrue(), cond);
+    Builder.CreateStore(object, ptr);
+  } else {
+    cond = 0;
+    ptr = object;
+  }
+
+  EHStack.pushCleanup<CallObjCRelease>(getARCCleanupKind(), type, ptr, cond);
+  return object;
+}
+
+llvm::Value *CodeGenFunction::EmitObjCExtendObjectLifetime(QualType type,
+                                                           llvm::Value *value) {
+  return EmitARCRetainAutorelease(type, value);
+}
+
+
+static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM,
+                                                const llvm::FunctionType *type,
+                                                llvm::StringRef fnName) {
+  llvm::Constant *fn = CGM.CreateRuntimeFunction(type, fnName);
+
+  // In -fobjc-no-arc-runtime, emit weak references to the runtime
+  // support library.
+  if (CGM.getLangOptions().ObjCNoAutoRefCountRuntime)
+    if (llvm::Function *f = dyn_cast<llvm::Function>(fn))
+      f->setLinkage(llvm::Function::ExternalWeakLinkage);
+
+  return fn;
+}
+
+/// Perform an operation having the signature
+///   i8* (i8*)
+/// where a null input causes a no-op and returns null.
+static llvm::Value *emitARCValueOperation(CodeGenFunction &CGF,
+                                          llvm::Value *value,
+                                          llvm::Constant *&fn,
+                                          llvm::StringRef fnName) {
+  if (isa<llvm::ConstantPointerNull>(value)) return value;
+
+  if (!fn) {
+    std::vector<const llvm::Type*> args(1, CGF.Int8PtrTy);
+    const llvm::FunctionType *fnType =
+      llvm::FunctionType::get(CGF.Int8PtrTy, args, false);
+    fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
+  }
+
+  // Cast the argument to 'id'.
+  const llvm::Type *origType = value->getType();
+  value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
+
+  // Call the function.
+  llvm::CallInst *call = CGF.Builder.CreateCall(fn, value);
+  call->setDoesNotThrow();
+
+  // Cast the result back to the original type.
+  return CGF.Builder.CreateBitCast(call, origType);
+}
+
+/// Perform an operation having the following signature:
+///   i8* (i8**)
+static llvm::Value *emitARCLoadOperation(CodeGenFunction &CGF,
+                                         llvm::Value *addr,
+                                         llvm::Constant *&fn,
+                                         llvm::StringRef fnName) {
+  if (!fn) {
+    std::vector<const llvm::Type*> args(1, CGF.Int8PtrPtrTy);
+    const llvm::FunctionType *fnType =
+      llvm::FunctionType::get(CGF.Int8PtrTy, args, false);
+    fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
+  }
+
+  // Cast the argument to 'id*'.
+  const llvm::Type *origType = addr->getType();
+  addr = CGF.Builder.CreateBitCast(addr, CGF.Int8PtrPtrTy);
+
+  // Call the function.
+  llvm::CallInst *call = CGF.Builder.CreateCall(fn, addr);
+  call->setDoesNotThrow();
+
+  // Cast the result back to a dereference of the original type.
+  llvm::Value *result = call;
+  if (origType != CGF.Int8PtrPtrTy)
+    result = CGF.Builder.CreateBitCast(result,
+                        cast<llvm::PointerType>(origType)->getElementType());
+
+  return result;
+}
+
+/// Perform an operation having the following signature:
+///   i8* (i8**, i8*)
+static llvm::Value *emitARCStoreOperation(CodeGenFunction &CGF,
+                                          llvm::Value *addr,
+                                          llvm::Value *value,
+                                          llvm::Constant *&fn,
+                                          llvm::StringRef fnName,
+                                          bool ignored) {
+  assert(cast<llvm::PointerType>(addr->getType())->getElementType()
+           == value->getType());
+
+  if (!fn) {
+    std::vector<const llvm::Type*> argTypes(2);
+    argTypes[0] = CGF.Int8PtrPtrTy;
+    argTypes[1] = CGF.Int8PtrTy;
+
+    const llvm::FunctionType *fnType
+      = llvm::FunctionType::get(CGF.Int8PtrTy, argTypes, false);
+    fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
+  }
+
+  const llvm::Type *origType = value->getType();
+
+  addr = CGF.Builder.CreateBitCast(addr, CGF.Int8PtrPtrTy);
+  value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
+    
+  llvm::CallInst *result = CGF.Builder.CreateCall2(fn, addr, value);
+  result->setDoesNotThrow();
+
+  if (ignored) return 0;
+
+  return CGF.Builder.CreateBitCast(result, origType);
+}
+
+/// Perform an operation having the following signature:
+///   void (i8**, i8**)
+static void emitARCCopyOperation(CodeGenFunction &CGF,
+                                 llvm::Value *dst,
+                                 llvm::Value *src,
+                                 llvm::Constant *&fn,
+                                 llvm::StringRef fnName) {
+  assert(dst->getType() == src->getType());
+
+  if (!fn) {
+    std::vector<const llvm::Type*> argTypes(2, CGF.Int8PtrPtrTy);
+    const llvm::FunctionType *fnType
+      = llvm::FunctionType::get(CGF.Builder.getVoidTy(), argTypes, false);
+    fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
+  }
+
+  dst = CGF.Builder.CreateBitCast(dst, CGF.Int8PtrPtrTy);
+  src = CGF.Builder.CreateBitCast(src, CGF.Int8PtrPtrTy);
+    
+  llvm::CallInst *result = CGF.Builder.CreateCall2(fn, dst, src);
+  result->setDoesNotThrow();
+}
+
+/// Produce the code to do a retain.  Based on the type, calls one of:
+///   call i8* @objc_retain(i8* %value)
+///   call i8* @objc_retainBlock(i8* %value)
+llvm::Value *CodeGenFunction::EmitARCRetain(QualType type, llvm::Value *value) {
+  if (type->isBlockPointerType())
+    return EmitARCRetainBlock(value);
+  else
+    return EmitARCRetainNonBlock(value);
+}
+
+/// Retain the given object, with normal retain semantics.
+///   call i8* @objc_retain(i8* %value)
+llvm::Value *CodeGenFunction::EmitARCRetainNonBlock(llvm::Value *value) {
+  return emitARCValueOperation(*this, value,
+                               CGM.getARCEntrypoints().objc_retain,
+                               "objc_retain");
+}
+
+/// Retain the given block, with _Block_copy semantics.
+///   call i8* @objc_retainBlock(i8* %value)
+llvm::Value *CodeGenFunction::EmitARCRetainBlock(llvm::Value *value) {
+  return emitARCValueOperation(*this, value,
+                               CGM.getARCEntrypoints().objc_retainBlock,
+                               "objc_retainBlock");
+}
+
+/// Retain the given object which is the result of a function call.
+///   call i8* @objc_retainAutoreleasedReturnValue(i8* %value)
+///
+/// Yes, this function name is one character away from a different
+/// call with completely different semantics.
+llvm::Value *
+CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
+  // Fetch the void(void) inline asm which marks that we're going to
+  // retain the autoreleased return value.
+  llvm::InlineAsm *&marker
+    = CGM.getARCEntrypoints().retainAutoreleasedReturnValueMarker;
+  if (!marker) {
+    llvm::StringRef assembly
+      = CGM.getTargetCodeGenInfo()
+           .getARCRetainAutoreleasedReturnValueMarker();
+
+    // If we have an empty assembly string, there's nothing to do.
+    if (assembly.empty()) {
+
+    // Otherwise, at -O0, build an inline asm that we're going to call
+    // in a moment.
+    } else if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
+      llvm::FunctionType *type =
+        llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()),
+                                /*variadic*/ false);
+      
+      marker = llvm::InlineAsm::get(type, assembly, "", /*sideeffects*/ true);
+
+    // If we're at -O1 and above, we don't want to litter the code
+    // with this marker yet, so leave a breadcrumb for the ARC
+    // optimizer to pick up.
+    } else {
+      llvm::NamedMDNode *metadata =
+        CGM.getModule().getOrInsertNamedMetadata(
+                            "clang.arc.retainAutoreleasedReturnValueMarker");
+      assert(metadata->getNumOperands() <= 1);
+      if (metadata->getNumOperands() == 0) {
+        llvm::Value *string = llvm::MDString::get(getLLVMContext(), assembly);
+        llvm::Value *args[] = { string };
+        metadata->addOperand(llvm::MDNode::get(getLLVMContext(), args));
+      }
+    }
+  }
+
+  // Call the marker asm if we made one, which we do only at -O0.
+  if (marker) Builder.CreateCall(marker);
+
+  return emitARCValueOperation(*this, value,
+                     CGM.getARCEntrypoints().objc_retainAutoreleasedReturnValue,
+                               "objc_retainAutoreleasedReturnValue");
+}
+
+/// Release the given object.
+///   call void @objc_release(i8* %value)
+void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) {
+  if (isa<llvm::ConstantPointerNull>(value)) return;
+
+  llvm::Constant *&fn = CGM.getARCEntrypoints().objc_release;
+  if (!fn) {
+    std::vector<const llvm::Type*> args(1, Int8PtrTy);
+    const llvm::FunctionType *fnType =
+      llvm::FunctionType::get(Builder.getVoidTy(), args, false);
+    fn = createARCRuntimeFunction(CGM, fnType, "objc_release");
+  }
+
+  // Cast the argument to 'id'.
+  value = Builder.CreateBitCast(value, Int8PtrTy);
+
+  // Call objc_release.
+  llvm::CallInst *call = Builder.CreateCall(fn, value);
+  call->setDoesNotThrow();
+
+  if (!precise) {
+    llvm::SmallVector<llvm::Value*,1> args;
+    call->setMetadata("clang.imprecise_release",
+                      llvm::MDNode::get(Builder.getContext(), args));
+  }
+}
+
+/// Store into a strong object.  Always calls this:
+///   call void @objc_storeStrong(i8** %addr, i8* %value)
+llvm::Value *CodeGenFunction::EmitARCStoreStrongCall(llvm::Value *addr,
+                                                     llvm::Value *value,
+                                                     bool ignored) {
+  assert(cast<llvm::PointerType>(addr->getType())->getElementType()
+           == value->getType());
+
+  llvm::Constant *&fn = CGM.getARCEntrypoints().objc_storeStrong;
+  if (!fn) {
+    const llvm::Type *argTypes[] = { Int8PtrPtrTy, Int8PtrTy };
+    const llvm::FunctionType *fnType
+      = llvm::FunctionType::get(Builder.getVoidTy(), argTypes, false);
+    fn = createARCRuntimeFunction(CGM, fnType, "objc_storeStrong");
+  }
+
+  addr = Builder.CreateBitCast(addr, Int8PtrPtrTy);
+  llvm::Value *castValue = Builder.CreateBitCast(value, Int8PtrTy);
+  
+  Builder.CreateCall2(fn, addr, castValue)->setDoesNotThrow();
+
+  if (ignored) return 0;
+  return value;
+}
+
+/// Store into a strong object.  Sometimes calls this:
+///   call void @objc_storeStrong(i8** %addr, i8* %value)
+/// Other times, breaks it down into components.
+llvm::Value *CodeGenFunction::EmitARCStoreStrong(LValue dst, QualType type,
+                                                 llvm::Value *newValue,
+                                                 bool ignored) {
+  bool isBlock = type->isBlockPointerType();
+
+  // Use a store barrier at -O0 unless this is a block type or the
+  // lvalue is inadequately aligned.
+  if (shouldUseFusedARCCalls() &&
+      !isBlock &&
+      !(dst.getAlignment() && dst.getAlignment() < PointerAlignInBytes)) {
+    return EmitARCStoreStrongCall(dst.getAddress(), newValue, ignored);
+  }
+
+  // Otherwise, split it out.
+
+  // Retain the new value.
+  newValue = EmitARCRetain(type, newValue);
+
+  // Read the old value.
+  llvm::Value *oldValue =
+    EmitLoadOfScalar(dst.getAddress(), dst.isVolatileQualified(),
+                     dst.getAlignment(), type, dst.getTBAAInfo());
+
+  // Store.  We do this before the release so that any deallocs won't
+  // see the old value.
+  EmitStoreOfScalar(newValue, dst.getAddress(),
+                    dst.isVolatileQualified(), dst.getAlignment(),
+                    type, dst.getTBAAInfo());
+
+  // Finally, release the old value.
+  EmitARCRelease(oldValue, /*precise*/ false);
+
+  return newValue;
+}
+
+/// Autorelease the given object.
+///   call i8* @objc_autorelease(i8* %value)
+llvm::Value *CodeGenFunction::EmitARCAutorelease(llvm::Value *value) {
+  return emitARCValueOperation(*this, value,
+                               CGM.getARCEntrypoints().objc_autorelease,
+                               "objc_autorelease");
+}
+
+/// Autorelease the given object.
+///   call i8* @objc_autoreleaseReturnValue(i8* %value)
+llvm::Value *
+CodeGenFunction::EmitARCAutoreleaseReturnValue(llvm::Value *value) {
+  return emitARCValueOperation(*this, value,
+                            CGM.getARCEntrypoints().objc_autoreleaseReturnValue,
+                               "objc_autoreleaseReturnValue");
+}
+
+/// Do a fused retain/autorelease of the given object.
+///   call i8* @objc_retainAutoreleaseReturnValue(i8* %value)
+llvm::Value *
+CodeGenFunction::EmitARCRetainAutoreleaseReturnValue(llvm::Value *value) {
+  return emitARCValueOperation(*this, value,
+                     CGM.getARCEntrypoints().objc_retainAutoreleaseReturnValue,
+                               "objc_retainAutoreleaseReturnValue");
+}
+
+/// Do a fused retain/autorelease of the given object.
+///   call i8* @objc_retainAutorelease(i8* %value)
+/// or
+///   %retain = call i8* @objc_retainBlock(i8* %value)
+///   call i8* @objc_autorelease(i8* %retain)
+llvm::Value *CodeGenFunction::EmitARCRetainAutorelease(QualType type,
+                                                       llvm::Value *value) {
+  if (!type->isBlockPointerType())
+    return EmitARCRetainAutoreleaseNonBlock(value);
+
+  if (isa<llvm::ConstantPointerNull>(value)) return value;
+
+  const llvm::Type *origType = value->getType();
+  value = Builder.CreateBitCast(value, Int8PtrTy);
+  value = EmitARCRetainBlock(value);
+  value = EmitARCAutorelease(value);
+  return Builder.CreateBitCast(value, origType);
+}
+
+/// Do a fused retain/autorelease of the given object.
+///   call i8* @objc_retainAutorelease(i8* %value)
+llvm::Value *
+CodeGenFunction::EmitARCRetainAutoreleaseNonBlock(llvm::Value *value) {
+  return emitARCValueOperation(*this, value,
+                               CGM.getARCEntrypoints().objc_retainAutorelease,
+                               "objc_retainAutorelease");
+}
+
+/// i8* @objc_loadWeak(i8** %addr)
+/// Essentially objc_autorelease(objc_loadWeakRetained(addr)).
+llvm::Value *CodeGenFunction::EmitARCLoadWeak(llvm::Value *addr) {
+  return emitARCLoadOperation(*this, addr,
+                              CGM.getARCEntrypoints().objc_loadWeak,
+                              "objc_loadWeak");
+}
+
+/// i8* @objc_loadWeakRetained(i8** %addr)
+llvm::Value *CodeGenFunction::EmitARCLoadWeakRetained(llvm::Value *addr) {
+  return emitARCLoadOperation(*this, addr,
+                              CGM.getARCEntrypoints().objc_loadWeakRetained,
+                              "objc_loadWeakRetained");
+}
+
+/// i8* @objc_storeWeak(i8** %addr, i8* %value)
+/// Returns %value.
+llvm::Value *CodeGenFunction::EmitARCStoreWeak(llvm::Value *addr,
+                                               llvm::Value *value,
+                                               bool ignored) {
+  return emitARCStoreOperation(*this, addr, value,
+                               CGM.getARCEntrypoints().objc_storeWeak,
+                               "objc_storeWeak", ignored);
+}
+
+/// i8* @objc_initWeak(i8** %addr, i8* %value)
+/// Returns %value.  %addr is known to not have a current weak entry.
+/// Essentially equivalent to:
+///   *addr = nil; objc_storeWeak(addr, value);
+void CodeGenFunction::EmitARCInitWeak(llvm::Value *addr, llvm::Value *value) {
+  // If we're initializing to null, just write null to memory; no need
+  // to get the runtime involved.  But don't do this if optimization
+  // is enabled, because accounting for this would make the optimizer
+  // much more complicated.
+  if (isa<llvm::ConstantPointerNull>(value) &&
+      CGM.getCodeGenOpts().OptimizationLevel == 0) {
+    Builder.CreateStore(value, addr);
+    return;
+  }
+
+  emitARCStoreOperation(*this, addr, value,
+                        CGM.getARCEntrypoints().objc_initWeak,
+                        "objc_initWeak", /*ignored*/ true);
+}
+
+/// void @objc_destroyWeak(i8** %addr)
+/// Essentially objc_storeWeak(addr, nil).
+void CodeGenFunction::EmitARCDestroyWeak(llvm::Value *addr) {
+  llvm::Constant *&fn = CGM.getARCEntrypoints().objc_destroyWeak;
+  if (!fn) {
+    std::vector<const llvm::Type*> args(1, Int8PtrPtrTy);
+    const llvm::FunctionType *fnType =
+      llvm::FunctionType::get(Builder.getVoidTy(), args, false);
+    fn = createARCRuntimeFunction(CGM, fnType, "objc_destroyWeak");
+  }
+
+  // Cast the argument to 'id*'.
+  addr = Builder.CreateBitCast(addr, Int8PtrPtrTy);
+
+  llvm::CallInst *call = Builder.CreateCall(fn, addr);
+  call->setDoesNotThrow();
+}
+
+/// void @objc_moveWeak(i8** %dest, i8** %src)
+/// Disregards the current value in %dest.  Leaves %src pointing to nothing.
+/// Essentially (objc_copyWeak(dest, src), objc_destroyWeak(src)).
+void CodeGenFunction::EmitARCMoveWeak(llvm::Value *dst, llvm::Value *src) {
+  emitARCCopyOperation(*this, dst, src,
+                       CGM.getARCEntrypoints().objc_moveWeak,
+                       "objc_moveWeak");
+}
+
+/// void @objc_copyWeak(i8** %dest, i8** %src)
+/// Disregards the current value in %dest.  Essentially
+///   objc_release(objc_initWeak(dest, objc_readWeakRetained(src)))
+void CodeGenFunction::EmitARCCopyWeak(llvm::Value *dst, llvm::Value *src) {
+  emitARCCopyOperation(*this, dst, src,
+                       CGM.getARCEntrypoints().objc_copyWeak,
+                       "objc_copyWeak");
+}
+
+/// Produce the code to do a objc_autoreleasepool_push.
+///   call i8* @objc_autoreleasePoolPush(void)
+llvm::Value *CodeGenFunction::EmitObjCAutoreleasePoolPush() {
+  llvm::Constant *&fn = CGM.getRREntrypoints().objc_autoreleasePoolPush;
+  if (!fn) {
+    const llvm::FunctionType *fnType =
+      llvm::FunctionType::get(Int8PtrTy, false);
+    fn = createARCRuntimeFunction(CGM, fnType, "objc_autoreleasePoolPush");
+  }
+
+  llvm::CallInst *call = Builder.CreateCall(fn);
+  call->setDoesNotThrow();
+
+  return call;
+}
+
+/// Produce the code to do a primitive release.
+///   call void @objc_autoreleasePoolPop(i8* %ptr)
+void CodeGenFunction::EmitObjCAutoreleasePoolPop(llvm::Value *value) {
+  assert(value->getType() == Int8PtrTy);
+
+  llvm::Constant *&fn = CGM.getRREntrypoints().objc_autoreleasePoolPop;
+  if (!fn) {
+    std::vector<const llvm::Type*> args(1, Int8PtrTy);
+    const llvm::FunctionType *fnType =
+      llvm::FunctionType::get(Builder.getVoidTy(), args, false);
+
+    // We don't want to use a weak import here; instead we should not
+    // fall into this path.
+    fn = createARCRuntimeFunction(CGM, fnType, "objc_autoreleasePoolPop");
+  }
+
+  llvm::CallInst *call = Builder.CreateCall(fn, value);
+  call->setDoesNotThrow();
+}
+
+/// Produce the code to do an MRR version objc_autoreleasepool_push.
+/// Which is: [[NSAutoreleasePool alloc] init];
+/// Where alloc is declared as: + (id) alloc; in NSAutoreleasePool class.
+/// init is declared as: - (id) init; in its NSObject super class.
+///
+llvm::Value *CodeGenFunction::EmitObjCMRRAutoreleasePoolPush() {
+  CGObjCRuntime &Runtime = CGM.getObjCRuntime();
+  llvm::Value *Receiver = Runtime.EmitNSAutoreleasePoolClassRef(Builder);
+  // [NSAutoreleasePool alloc]
+  IdentifierInfo *II = &CGM.getContext().Idents.get("alloc");
+  Selector AllocSel = getContext().Selectors.getSelector(0, &II);
+  CallArgList Args;
+  RValue AllocRV =  
+    Runtime.GenerateMessageSend(*this, ReturnValueSlot(), 
+                                getContext().getObjCIdType(),
+                                AllocSel, Receiver, Args); 
+
+  // [Receiver init]
+  Receiver = AllocRV.getScalarVal();
+  II = &CGM.getContext().Idents.get("init");
+  Selector InitSel = getContext().Selectors.getSelector(0, &II);
+  RValue InitRV =
+    Runtime.GenerateMessageSend(*this, ReturnValueSlot(),
+                                getContext().getObjCIdType(),
+                                InitSel, Receiver, Args); 
+  return InitRV.getScalarVal();
+}
+
+/// Produce the code to do a primitive release.
+/// [tmp drain];
+void CodeGenFunction::EmitObjCMRRAutoreleasePoolPop(llvm::Value *Arg) {
+  IdentifierInfo *II = &CGM.getContext().Idents.get("drain");
+  Selector DrainSel = getContext().Selectors.getSelector(0, &II);
+  CallArgList Args;
+  CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(),
+                              getContext().VoidTy, DrainSel, Arg, Args); 
+}
+
+namespace {
+  struct ObjCReleasingCleanup : EHScopeStack::Cleanup {
+  private:
+    QualType type;
+    llvm::Value *addr;
+
+  protected:
+    ObjCReleasingCleanup(QualType type, llvm::Value *addr)
+      : type(type), addr(addr) {}
+
+    virtual llvm::Value *getAddress(CodeGenFunction &CGF,
+                                    llvm::Value *addr) {
+      return addr;
+    }
+
+    virtual void release(CodeGenFunction &CGF,
+                         QualType type,
+                         llvm::Value *addr) = 0;
+
+  public:
+    void Emit(CodeGenFunction &CGF, bool isForEH) {
+      const ArrayType *arrayType = CGF.getContext().getAsArrayType(type);
+
+      llvm::Value *addr = getAddress(CGF, this->addr);
+
+      // If we don't have an array type, this is easy.
+      if (!arrayType)
+        return release(CGF, type, addr);
+
+      llvm::Value *begin = addr;
+      QualType baseType;
+
+      // Otherwise, this is more painful.
+      llvm::Value *count = emitArrayLength(CGF, arrayType, baseType,
+                                           begin);
+
+      assert(baseType == CGF.getContext().getBaseElementType(arrayType));
+
+      llvm::BasicBlock *incomingBB = CGF.Builder.GetInsertBlock();
+
+      //   id *cur = begin;
+      //   id *end = begin + count;
+      llvm::Value *end =
+        CGF.Builder.CreateInBoundsGEP(begin, count, "array.end");
+
+      // loopBB:
+      llvm::BasicBlock *loopBB = CGF.createBasicBlock("release-loop");
+      CGF.EmitBlock(loopBB);
+
+      llvm::PHINode *cur = CGF.Builder.CreatePHI(begin->getType(), 2, "cur");
+      cur->addIncoming(begin, incomingBB);
+
+      //   if (cur == end) goto endBB;
+      llvm::Value *eq = CGF.Builder.CreateICmpEQ(cur, end, "release-loop.done");
+      llvm::BasicBlock *bodyBB = CGF.createBasicBlock("release-loop.body");
+      llvm::BasicBlock *endBB = CGF.createBasicBlock("release-loop.cont");
+      CGF.Builder.CreateCondBr(eq, endBB, bodyBB);
+      CGF.EmitBlock(bodyBB);
+
+      // Release the value at 'cur'.
+      release(CGF, baseType, cur);
+
+      //   ++cur;
+      //   goto loopBB;
+      llvm::Value *next = CGF.Builder.CreateConstInBoundsGEP1_32(cur, 1);
+      cur->addIncoming(next, CGF.Builder.GetInsertBlock());
+      CGF.Builder.CreateBr(loopBB);
+
+      // endBB:
+      CGF.EmitBlock(endBB);
+    }
+
+  private:
+    /// Computes the length of an array in elements, as well
+    /// as the base
+    static llvm::Value *emitArrayLength(CodeGenFunction &CGF,
+                                        const ArrayType *origArrayType,
+                                        QualType &baseType,
+                                        llvm::Value *&addr) {
+      ASTContext &Ctx = CGF.getContext();
+      const ArrayType *arrayType = origArrayType;
+
+      // If it's a VLA, we have to load the stored size.  Note that
+      // this is the size of the VLA in bytes, not its size in elements.
+      llvm::Value *vlaSizeInBytes = 0;
+      if (isa<VariableArrayType>(arrayType)) {
+        vlaSizeInBytes = CGF.GetVLASize(cast<VariableArrayType>(arrayType));
+
+        // Walk into all VLAs.  This doesn't require changes to addr,
+        // which has type T* where T is the first non-VLA element type.
+        do {
+          QualType elementType = arrayType->getElementType();
+          arrayType = Ctx.getAsArrayType(elementType);
+
+          // If we only have VLA components, 'addr' requires no adjustment.
+          if (!arrayType) {
+            baseType = elementType;
+            return divideVLASizeByBaseType(CGF, vlaSizeInBytes, baseType);
+          }
+        } while (isa<VariableArrayType>(arrayType));
+
+        // We get out here only if we find a constant array type
+        // inside the VLA.
+      }
+
+      // We have some number of constant-length arrays, so addr should
+      // have LLVM type [M x [N x [...]]]*.  Build a GEP that walks
+      // down to the first element of addr.
+      llvm::SmallVector<llvm::Value*, 8> gepIndices;
+
+      // GEP down to the array type.
+      llvm::ConstantInt *zero = CGF.Builder.getInt32(0);
+      gepIndices.push_back(zero);
+
+      // It's more efficient to calculate the count from the LLVM
+      // constant-length arrays than to re-evaluate the array bounds.
+      uint64_t countFromCLAs = 1;
+
+      const llvm::ArrayType *llvmArrayType =
+        cast<llvm::ArrayType>(
+          cast<llvm::PointerType>(addr->getType())->getElementType());
+      while (true) {
+        assert(isa<ConstantArrayType>(arrayType));
+        assert(cast<ConstantArrayType>(arrayType)->getSize().getZExtValue()
+                 == llvmArrayType->getNumElements());
+
+        gepIndices.push_back(zero);
+        countFromCLAs *= llvmArrayType->getNumElements();
+
+        llvmArrayType =
+          dyn_cast<llvm::ArrayType>(llvmArrayType->getElementType());
+        if (!llvmArrayType) break;
+
+        arrayType = Ctx.getAsArrayType(arrayType->getElementType());
+        assert(arrayType && "LLVM and Clang types are out-of-synch");
+      }
+
+      // Create the actual GEP.
+      addr = CGF.Builder.CreateInBoundsGEP(addr, gepIndices.begin(),
+                                           gepIndices.end(), "array.begin");
+
+      baseType = arrayType->getElementType();
+
+      // If we had an VLA dimensions, we need to use the captured size.
+      if (vlaSizeInBytes)
+        return divideVLASizeByBaseType(CGF, vlaSizeInBytes, baseType);
+
+      // Otherwise, use countFromCLAs.
+      assert(countFromCLAs == (uint64_t)
+               (Ctx.getTypeSizeInChars(origArrayType).getQuantity() /
+                Ctx.getTypeSizeInChars(baseType).getQuantity()));
+
+      return llvm::ConstantInt::get(CGF.IntPtrTy, countFromCLAs);
+    }
+
+    static llvm::Value *divideVLASizeByBaseType(CodeGenFunction &CGF,
+                                                llvm::Value *vlaSizeInBytes,
+                                                QualType baseType) {
+      // Divide the base type size back out of the 
+      CharUnits baseSize = CGF.getContext().getTypeSizeInChars(baseType);
+      llvm::Value *baseSizeInBytes =
+        llvm::ConstantInt::get(vlaSizeInBytes->getType(),
+                               baseSize.getQuantity());
+
+      return CGF.Builder.CreateUDiv(vlaSizeInBytes, baseSizeInBytes,
+                                    "array.vla-count");
+    }
+  };
+
+  /// A cleanup that calls @objc_release on all the objects to release.
+  struct CallReleaseForObject : ObjCReleasingCleanup {
+    bool precise;
+    CallReleaseForObject(QualType type, llvm::Value *addr, bool precise)
+      : ObjCReleasingCleanup(type, addr), precise(precise) {}
+
+    void release(CodeGenFunction &CGF, QualType type, llvm::Value *addr) {
+      llvm::Value *ptr = CGF.Builder.CreateLoad(addr, "tmp");
+      CGF.EmitARCRelease(ptr, precise);
+    }
+  };
+
+  /// A cleanup that calls @objc_storeStrong(nil) on all the objects to
+  /// release in an ivar.
+  struct CallReleaseForIvar : ObjCReleasingCleanup {
+    const ObjCIvarDecl *ivar;
+    CallReleaseForIvar(const ObjCIvarDecl *ivar, llvm::Value *self)
+      : ObjCReleasingCleanup(ivar->getType(), self), ivar(ivar) {}
+
+    llvm::Value *getAddress(CodeGenFunction &CGF, llvm::Value *addr) {
+      LValue lvalue
+        = CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), addr, ivar, /*CVR*/ 0);
+      return lvalue.getAddress();
+    }
+
+    void release(CodeGenFunction &CGF, QualType type, llvm::Value *addr) {
+      // Release ivars by storing nil into them;  it just makes things easier.
+      llvm::Value *null = getNullForVariable(addr);
+      CGF.EmitARCStoreStrongCall(addr, null, /*ignored*/ true);
+    }
+  };
+
+  /// A cleanup that calls @objc_release on all of the objects to release in
+  /// a field.
+  struct CallReleaseForField : CallReleaseForObject {
+    const FieldDecl *Field;
+    
+    explicit CallReleaseForField(const FieldDecl *Field)
+      : CallReleaseForObject(Field->getType(), 0, /*precise=*/true),
+        Field(Field) { }
+    
+    llvm::Value *getAddress(CodeGenFunction &CGF, llvm::Value *) {
+      llvm::Value *This = CGF.LoadCXXThis();      
+      LValue LV = CGF.EmitLValueForField(This, Field, 0);
+      return LV.getAddress();
+    }
+  };
+  
+  /// A cleanup that calls @objc_weak_release on all the objects to
+  /// release in an object.
+  struct CallWeakReleaseForObject : ObjCReleasingCleanup {
+    CallWeakReleaseForObject(QualType type, llvm::Value *addr)
+      : ObjCReleasingCleanup(type, addr) {}
+
+    void release(CodeGenFunction &CGF, QualType type, llvm::Value *addr) {
+      CGF.EmitARCDestroyWeak(addr);
+    }
+  };
+
+  
+  /// A cleanup that calls @objc_weak_release on all the objects to
+  /// release in an ivar.
+  struct CallWeakReleaseForIvar : CallWeakReleaseForObject {
+    const ObjCIvarDecl *ivar;
+    CallWeakReleaseForIvar(const ObjCIvarDecl *ivar, llvm::Value *self)
+    : CallWeakReleaseForObject(ivar->getType(), self), ivar(ivar) {}
+    
+    llvm::Value *getAddress(CodeGenFunction &CGF, llvm::Value *addr) {
+      LValue lvalue
+      = CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), addr, ivar, /*CVR*/ 0);
+      return lvalue.getAddress();
+    }
+  };
+
+  /// A cleanup that calls @objc_weak_release on all the objects to
+  /// release in a field;
+  struct CallWeakReleaseForField : CallWeakReleaseForObject {
+    const FieldDecl *Field;
+    CallWeakReleaseForField(const FieldDecl *Field)
+      : CallWeakReleaseForObject(Field->getType(), 0), Field(Field) {}
+    
+    llvm::Value *getAddress(CodeGenFunction &CGF, llvm::Value *) {
+      llvm::Value *This = CGF.LoadCXXThis();      
+      LValue LV = CGF.EmitLValueForField(This, Field, 0);
+      return LV.getAddress();
+    }
+  };
+  
+  struct CallObjCAutoreleasePoolObject : EHScopeStack::Cleanup {
+    llvm::Value *Token;
+
+    CallObjCAutoreleasePoolObject(llvm::Value *token) : Token(token) {}
+
+    void Emit(CodeGenFunction &CGF, bool isForEH) {
+      CGF.EmitObjCAutoreleasePoolPop(Token);
+    }
+  };
+  struct CallObjCMRRAutoreleasePoolObject : EHScopeStack::Cleanup {
+    llvm::Value *Token;
+
+    CallObjCMRRAutoreleasePoolObject(llvm::Value *token) : Token(token) {}
+
+    void Emit(CodeGenFunction &CGF, bool isForEH) {
+      CGF.EmitObjCMRRAutoreleasePoolPop(Token);
+    }
+  };
+}
+
+void CodeGenFunction::EmitObjCAutoreleasePoolCleanup(llvm::Value *Ptr) {
+  if (CGM.getLangOptions().ObjCAutoRefCount)
+    EHStack.pushCleanup<CallObjCAutoreleasePoolObject>(NormalCleanup, Ptr);
+  else
+    EHStack.pushCleanup<CallObjCMRRAutoreleasePoolObject>(NormalCleanup, Ptr);
+}
+
+/// PushARCReleaseCleanup - Enter a cleanup to perform a release on a
+/// given object or array of objects.
+void CodeGenFunction::PushARCReleaseCleanup(CleanupKind cleanupKind,
+                                            QualType type,
+                                            llvm::Value *addr,
+                                            bool precise) {
+  EHStack.pushCleanup<CallReleaseForObject>(cleanupKind, type, addr, precise);
+}
+
+/// PushARCWeakReleaseCleanup - Enter a cleanup to perform a weak
+/// release on the given object or array of objects.
+void CodeGenFunction::PushARCWeakReleaseCleanup(CleanupKind cleanupKind,
+                                                QualType type,
+                                                llvm::Value *addr) {
+  EHStack.pushCleanup<CallWeakReleaseForObject>(cleanupKind, type, addr);
+}
+
+/// PushARCReleaseCleanup - Enter a cleanup to perform a release on a
+/// given object or array of objects.
+void CodeGenFunction::PushARCFieldReleaseCleanup(CleanupKind cleanupKind,
+                                                 const FieldDecl *field) {
+  EHStack.pushCleanup<CallReleaseForField>(cleanupKind, field);
+}
+
+/// PushARCWeakReleaseCleanup - Enter a cleanup to perform a weak
+/// release on the given object or array of objects.
+void CodeGenFunction::PushARCFieldWeakReleaseCleanup(CleanupKind cleanupKind,
+                                                     const FieldDecl *field) {
+  EHStack.pushCleanup<CallWeakReleaseForField>(cleanupKind, field);
+}
+
+static void pushReleaseForIvar(CodeGenFunction &CGF, ObjCIvarDecl *ivar,
+                               llvm::Value *self) {
+  CGF.EHStack.pushCleanup<CallReleaseForIvar>(CGF.getARCCleanupKind(),
+                                              ivar, self);
+}
+
+static void pushWeakReleaseForIvar(CodeGenFunction &CGF, ObjCIvarDecl *ivar,
+                                   llvm::Value *self) {
+  CGF.EHStack.pushCleanup<CallWeakReleaseForIvar>(CGF.getARCCleanupKind(),
+                                                  ivar, self);
+}
+
+static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF,
+                                                  LValue lvalue,
+                                                  QualType type) {
+  switch (type.getObjCLifetime()) {
+  case Qualifiers::OCL_None:
+  case Qualifiers::OCL_ExplicitNone:
+  case Qualifiers::OCL_Strong:
+  case Qualifiers::OCL_Autoreleasing:
+    return TryEmitResult(CGF.EmitLoadOfLValue(lvalue, type).getScalarVal(),
+                         false);
+
+  case Qualifiers::OCL_Weak:
+    return TryEmitResult(CGF.EmitARCLoadWeakRetained(lvalue.getAddress()),
+                         true);
+  }
+
+  llvm_unreachable("impossible lifetime!");
+  return TryEmitResult();
+}
+
+static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF,
+                                                  const Expr *e) {
+  e = e->IgnoreParens();
+  QualType type = e->getType();
+
+  // As a very special optimization, in ARC++, if the l-value is the
+  // result of a non-volatile assignment, do a simple retain of the
+  // result of the call to objc_storeWeak instead of reloading.
+  if (CGF.getLangOptions().CPlusPlus &&
+      !type.isVolatileQualified() &&
+      type.getObjCLifetime() == Qualifiers::OCL_Weak &&
+      isa<BinaryOperator>(e) &&
+      cast<BinaryOperator>(e)->getOpcode() == BO_Assign)
+    return TryEmitResult(CGF.EmitScalarExpr(e), false);
+
+  return tryEmitARCRetainLoadOfScalar(CGF, CGF.EmitLValue(e), type);
+}
+
+static llvm::Value *emitARCRetainAfterCall(CodeGenFunction &CGF,
+                                           llvm::Value *value);
+
+/// Given that the given expression is some sort of call (which does
+/// not return retained), emit a retain following it.
+static llvm::Value *emitARCRetainCall(CodeGenFunction &CGF, const Expr *e) {
+  llvm::Value *value = CGF.EmitScalarExpr(e);
+  return emitARCRetainAfterCall(CGF, value);
+}
+
+static llvm::Value *emitARCRetainAfterCall(CodeGenFunction &CGF,
+                                           llvm::Value *value) {
+  if (llvm::CallInst *call = dyn_cast<llvm::CallInst>(value)) {
+    CGBuilderTy::InsertPoint ip = CGF.Builder.saveIP();
+
+    // Place the retain immediately following the call.
+    CGF.Builder.SetInsertPoint(call->getParent(),
+                               ++llvm::BasicBlock::iterator(call));
+    value = CGF.EmitARCRetainAutoreleasedReturnValue(value);
+
+    CGF.Builder.restoreIP(ip);
+    return value;
+  } else if (llvm::InvokeInst *invoke = dyn_cast<llvm::InvokeInst>(value)) {
+    CGBuilderTy::InsertPoint ip = CGF.Builder.saveIP();
+
+    // Place the retain at the beginning of the normal destination block.
+    llvm::BasicBlock *BB = invoke->getNormalDest();
+    CGF.Builder.SetInsertPoint(BB, BB->begin());
+    value = CGF.EmitARCRetainAutoreleasedReturnValue(value);
+
+    CGF.Builder.restoreIP(ip);
+    return value;
+
+  // Bitcasts can arise because of related-result returns.  Rewrite
+  // the operand.
+  } else if (llvm::BitCastInst *bitcast = dyn_cast<llvm::BitCastInst>(value)) {
+    llvm::Value *operand = bitcast->getOperand(0);
+    operand = emitARCRetainAfterCall(CGF, operand);
+    bitcast->setOperand(0, operand);
+    return bitcast;
+
+  // Generic fall-back case.
+  } else {
+    // Retain using the non-block variant: we never need to do a copy
+    // of a block that's been returned to us.
+    return CGF.EmitARCRetainNonBlock(value);
+  }
+}
+
+static TryEmitResult
+tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
+  QualType originalType = e->getType();
+
+  // The desired result type, if it differs from the type of the
+  // ultimate opaque expression.
+  const llvm::Type *resultType = 0;
+
+  while (true) {
+    e = e->IgnoreParens();
+
+    // There's a break at the end of this if-chain;  anything
+    // that wants to keep looping has to explicitly continue.
+    if (const CastExpr *ce = dyn_cast<CastExpr>(e)) {
+      switch (ce->getCastKind()) {
+      // No-op casts don't change the type, so we just ignore them.
+      case CK_NoOp:
+        e = ce->getSubExpr();
+        continue;
+
+      case CK_LValueToRValue: {
+        TryEmitResult loadResult
+          = tryEmitARCRetainLoadOfScalar(CGF, ce->getSubExpr());
+        if (resultType) {
+          llvm::Value *value = loadResult.getPointer();
+          value = CGF.Builder.CreateBitCast(value, resultType);
+          loadResult.setPointer(value);
+        }
+        return loadResult;
+      }
+
+      // These casts can change the type, so remember that and
+      // soldier on.  We only need to remember the outermost such
+      // cast, though.
+      case CK_AnyPointerToObjCPointerCast:
+      case CK_AnyPointerToBlockPointerCast:
+      case CK_BitCast:
+        if (!resultType)
+          resultType = CGF.ConvertType(ce->getType());
+        e = ce->getSubExpr();
+        assert(e->getType()->hasPointerRepresentation());
+        continue;
+
+      // For consumptions, just emit the subexpression and thus elide
+      // the retain/release pair.
+      case CK_ObjCConsumeObject: {
+        llvm::Value *result = CGF.EmitScalarExpr(ce->getSubExpr());
+        if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
+        return TryEmitResult(result, true);
+      }
+
+      case CK_GetObjCProperty: {
+        llvm::Value *result = emitARCRetainCall(CGF, ce);
+        if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
+        return TryEmitResult(result, true);
+      }
+
+      default:
+        break;
+      }
+
+    // Skip __extension__.
+    } else if (const UnaryOperator *op = dyn_cast<UnaryOperator>(e)) {
+      if (op->getOpcode() == UO_Extension) {
+        e = op->getSubExpr();
+        continue;
+      }
+
+    // For calls and message sends, use the retained-call logic.
+    // Delegate inits are a special case in that they're the only
+    // returns-retained expression that *isn't* surrounded by
+    // a consume.
+    } else if (isa<CallExpr>(e) ||
+               (isa<ObjCMessageExpr>(e) &&
+                !cast<ObjCMessageExpr>(e)->isDelegateInitCall())) {
+      llvm::Value *result = emitARCRetainCall(CGF, e);
+      if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
+      return TryEmitResult(result, true);
+    }
+
+    // Conservatively halt the search at any other expression kind.
+    break;
+  }
+
+  // We didn't find an obvious production, so emit what we've got and
+  // tell the caller that we didn't manage to retain.
+  llvm::Value *result = CGF.EmitScalarExpr(e);
+  if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
+  return TryEmitResult(result, false);
+}
+
+static llvm::Value *emitARCRetainLoadOfScalar(CodeGenFunction &CGF,
+                                                LValue lvalue,
+                                                QualType type) {
+  TryEmitResult result = tryEmitARCRetainLoadOfScalar(CGF, lvalue, type);
+  llvm::Value *value = result.getPointer();
+  if (!result.getInt())
+    value = CGF.EmitARCRetain(type, value);
+  return value;
+}
+
+/// EmitARCRetainScalarExpr - Semantically equivalent to
+/// EmitARCRetainObject(e->getType(), EmitScalarExpr(e)), but making a
+/// best-effort attempt to peephole expressions that naturally produce
+/// retained objects.
+llvm::Value *CodeGenFunction::EmitARCRetainScalarExpr(const Expr *e) {
+  TryEmitResult result = tryEmitARCRetainScalarExpr(*this, e);
+  llvm::Value *value = result.getPointer();
+  if (!result.getInt())
+    value = EmitARCRetain(e->getType(), value);
+  return value;
+}
+
+llvm::Value *
+CodeGenFunction::EmitARCRetainAutoreleaseScalarExpr(const Expr *e) {
+  TryEmitResult result = tryEmitARCRetainScalarExpr(*this, e);
+  llvm::Value *value = result.getPointer();
+  if (result.getInt())
+    value = EmitARCAutorelease(value);
+  else
+    value = EmitARCRetainAutorelease(e->getType(), value);
+  return value;
+}
+
+std::pair<LValue,llvm::Value*>
+CodeGenFunction::EmitARCStoreStrong(const BinaryOperator *e,
+                                    bool ignored) {
+  // Evaluate the RHS first.
+  TryEmitResult result = tryEmitARCRetainScalarExpr(*this, e->getRHS());
+  llvm::Value *value = result.getPointer();
+
+  LValue lvalue = EmitLValue(e->getLHS());
+
+  // If the RHS was emitted retained, expand this.
+  if (result.getInt()) {
+    llvm::Value *oldValue =
+      EmitLoadOfScalar(lvalue.getAddress(), lvalue.isVolatileQualified(),
+                       lvalue.getAlignment(), e->getType(),
+                       lvalue.getTBAAInfo());
+    EmitStoreOfScalar(value, lvalue.getAddress(),
+                      lvalue.isVolatileQualified(), lvalue.getAlignment(),
+                      e->getType(), lvalue.getTBAAInfo());
+    EmitARCRelease(oldValue, /*precise*/ false);
+  } else {
+    value = EmitARCStoreStrong(lvalue, e->getType(), value, ignored);
+  }
+
+  return std::pair<LValue,llvm::Value*>(lvalue, value);
+}
+
+std::pair<LValue,llvm::Value*>
+CodeGenFunction::EmitARCStoreAutoreleasing(const BinaryOperator *e) {
+  llvm::Value *value = EmitARCRetainAutoreleaseScalarExpr(e->getRHS());
+  LValue lvalue = EmitLValue(e->getLHS());
+
+  EmitStoreOfScalar(value, lvalue.getAddress(),
+                    lvalue.isVolatileQualified(), lvalue.getAlignment(),
+                    e->getType(), lvalue.getTBAAInfo());
+
+  return std::pair<LValue,llvm::Value*>(lvalue, value);
+}
+
+void CodeGenFunction::EmitObjCAutoreleasePoolStmt(
+                                             const ObjCAutoreleasePoolStmt &ARPS) {
+  const Stmt *subStmt = ARPS.getSubStmt();
+  const CompoundStmt &S = cast<CompoundStmt>(*subStmt);
+
+  CGDebugInfo *DI = getDebugInfo();
+  if (DI) {
+    DI->setLocation(S.getLBracLoc());
+    DI->EmitRegionStart(Builder);
+  }
+
+  // Keep track of the current cleanup stack depth.
+  RunCleanupsScope Scope(*this);
+  const llvm::Triple Triple = getContext().Target.getTriple();
+  if (CGM.getLangOptions().ObjCAutoRefCount ||
+      (CGM.isTargetDarwin() && 
+       ((Triple.getArch() == llvm::Triple::x86_64 && 
+         Triple.getDarwinMajorNumber() >= 11)
+        || (Triple.getEnvironmentName() == "iphoneos" && 
+            Triple.getDarwinMajorNumber() >= 5)))) {
+    llvm::Value *token = EmitObjCAutoreleasePoolPush();
+    EHStack.pushCleanup<CallObjCAutoreleasePoolObject>(NormalCleanup, token);
+  } else {
+    llvm::Value *token = EmitObjCMRRAutoreleasePoolPush();
+    EHStack.pushCleanup<CallObjCMRRAutoreleasePoolObject>(NormalCleanup, token);
+  }
+
+  for (CompoundStmt::const_body_iterator I = S.body_begin(),
+       E = S.body_end(); I != E; ++I)
+    EmitStmt(*I);
+
+  if (DI) {
+    DI->setLocation(S.getRBracLoc());
+    DI->EmitRegionEnd(Builder);
+  }
+}
 CGObjCRuntime::~CGObjCRuntime() {}

Modified: cfe/trunk/lib/CodeGen/CGObjCGNU.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCGNU.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjCGNU.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjCGNU.cpp Wed Jun 15 18:02:42 2011
@@ -969,7 +969,7 @@
 
   ActualArgs.add(RValue::get(EnforceType(Builder, Receiver, IdTy)), ASTIdTy);
   ActualArgs.add(RValue::get(cmd), CGF.getContext().getObjCSelType());
-  ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
+  ActualArgs.addFrom(CallArgs);
 
   CodeGenTypes &Types = CGM.getTypes();
   const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
@@ -1121,7 +1121,7 @@
   CallArgList ActualArgs;
   ActualArgs.add(RValue::get(Receiver), ASTIdTy);
   ActualArgs.add(RValue::get(cmd), CGF.getContext().getObjCSelType());
-  ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
+  ActualArgs.addFrom(CallArgs);
 
   CodeGenTypes &Types = CGM.getTypes();
   const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,

Modified: cfe/trunk/lib/CodeGen/CGObjCMac.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCMac.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjCMac.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjCMac.cpp Wed Jun 15 18:02:42 2011
@@ -63,10 +63,13 @@
   /// The default messenger, used for sends whose ABI is unchanged from
   /// the all-integer/pointer case.
   llvm::Constant *getMessageSendFn() const {
+    // Add the non-lazy-bind attribute, since objc_msgSend is likely to
+    // be called a lot.
     const llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
     return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
                                                              params, true),
-                                     "objc_msgSend");
+                                     "objc_msgSend",
+                                     llvm::Attribute::NonLazyBind);
   }
 
   /// void objc_msgSend_stret (id, SEL, ...)
@@ -887,6 +890,11 @@
   llvm::Value *EmitClassRef(CGBuilderTy &Builder,
                             const ObjCInterfaceDecl *ID);
   
+  llvm::Value *EmitClassRefFromId(CGBuilderTy &Builder,
+                                  IdentifierInfo *II);
+  
+  llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder);
+  
   /// EmitSuperClassRef - Emits reference to class's main metadata class.
   llvm::Value *EmitSuperClassRef(const ObjCInterfaceDecl *ID);
 
@@ -1158,6 +1166,11 @@
   /// for the given class reference.
   llvm::Value *EmitClassRef(CGBuilderTy &Builder,
                             const ObjCInterfaceDecl *ID);
+  
+  llvm::Value *EmitClassRefFromId(CGBuilderTy &Builder,
+                                  IdentifierInfo *II);
+  
+  llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder);
 
   /// EmitSuperClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
   /// for the given super class reference.
@@ -1526,7 +1539,7 @@
     Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy, "tmp");
   ActualArgs.add(RValue::get(Arg0), Arg0Ty);
   ActualArgs.add(RValue::get(Sel), CGF.getContext().getObjCSelType());
-  ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
+  ActualArgs.addFrom(CallArgs);
 
   CodeGenTypes &Types = CGM.getTypes();
   const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs,
@@ -1562,7 +1575,7 @@
   if (FQT.isObjCGCStrong())
     return Qualifiers::Strong;
   
-  if (FQT.isObjCGCWeak())
+  if (FQT.isObjCGCWeak() || FQT.getObjCLifetime() == Qualifiers::OCL_Weak)
     return Qualifiers::Weak;
   
   if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType())
@@ -1579,7 +1592,8 @@
   llvm::Constant *nullPtr = 
     llvm::Constant::getNullValue(llvm::Type::getInt8PtrTy(VMContext));
 
-  if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC)
+  if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC &&
+      !CGM.getLangOptions().ObjCAutoRefCount)
     return nullPtr;
 
   bool hasUnion = false;
@@ -2129,7 +2143,7 @@
                      Interface->all_referenced_protocol_begin(),
                      Interface->all_referenced_protocol_end());
   unsigned Flags = eClassFlags_Factory;
-  if (ID->getNumIvarInitializers())
+  if (ID->hasCXXStructors())
     Flags |= eClassFlags_HasCXXStructors;
   unsigned Size =
     CGM.getContext().getASTObjCImplementationLayout(ID).getSize().getQuantity();
@@ -3461,25 +3475,35 @@
   return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.SymtabPtrTy);
 }
 
-llvm::Value *CGObjCMac::EmitClassRef(CGBuilderTy &Builder,
-                                     const ObjCInterfaceDecl *ID) {
-  LazySymbols.insert(ID->getIdentifier());
-
-  llvm::GlobalVariable *&Entry = ClassReferences[ID->getIdentifier()];
-
+llvm::Value *CGObjCMac::EmitClassRefFromId(CGBuilderTy &Builder,
+                                     IdentifierInfo *II) {
+  LazySymbols.insert(II);
+  
+  llvm::GlobalVariable *&Entry = ClassReferences[II];
+  
   if (!Entry) {
     llvm::Constant *Casted =
-      llvm::ConstantExpr::getBitCast(GetClassName(ID->getIdentifier()),
-                                     ObjCTypes.ClassPtrTy);
+    llvm::ConstantExpr::getBitCast(GetClassName(II),
+                                   ObjCTypes.ClassPtrTy);
     Entry =
-      CreateMetadataVar("\01L_OBJC_CLASS_REFERENCES_", Casted,
-                        "__OBJC,__cls_refs,literal_pointers,no_dead_strip",
-                        4, true);
+    CreateMetadataVar("\01L_OBJC_CLASS_REFERENCES_", Casted,
+                      "__OBJC,__cls_refs,literal_pointers,no_dead_strip",
+                      4, true);
   }
-
+  
   return Builder.CreateLoad(Entry, "tmp");
 }
 
+llvm::Value *CGObjCMac::EmitClassRef(CGBuilderTy &Builder,
+                                     const ObjCInterfaceDecl *ID) {
+  return EmitClassRefFromId(Builder, ID->getIdentifier());
+}
+
+llvm::Value *CGObjCMac::EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder) {
+  IdentifierInfo *II = &CGM.getContext().Idents.get("NSAutoreleasePool");
+  return EmitClassRefFromId(Builder, II);
+}
+
 llvm::Value *CGObjCMac::EmitSelector(CGBuilderTy &Builder, Selector Sel,
                                      bool lvalue) {
   llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
@@ -3567,12 +3591,18 @@
   uint64_t MaxFieldOffset = 0;
   uint64_t MaxSkippedFieldOffset = 0;
   uint64_t LastBitfieldOrUnnamedOffset = 0;
+  uint64_t FirstFieldDelta = 0;
 
   if (RecFields.empty())
     return;
   unsigned WordSizeInBits = CGM.getContext().Target.getPointerWidth(0);
   unsigned ByteSizeInBits = CGM.getContext().Target.getCharWidth();
-
+  if (!RD && CGM.getLangOptions().ObjCAutoRefCount) {
+    FieldDecl *FirstField = RecFields[0];
+    FirstFieldDelta = 
+      ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(FirstField));
+  }
+  
   for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
     FieldDecl *Field = RecFields[i];
     uint64_t FieldOffset;
@@ -3580,9 +3610,10 @@
       // Note that 'i' here is actually the field index inside RD of Field,
       // although this dependency is hidden.
       const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
-      FieldOffset = RL.getFieldOffset(i) / ByteSizeInBits;
+      FieldOffset = (RL.getFieldOffset(i) / ByteSizeInBits) - FirstFieldDelta;
     } else
-      FieldOffset = ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(Field));
+      FieldOffset = 
+        ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(Field)) - FirstFieldDelta;
 
     // Skip over unnamed or bitfields
     if (!Field->getIdentifier() || Field->isBitField()) {
@@ -3861,12 +3892,16 @@
   bool hasUnion = false;
 
   const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext);
-  if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC)
+  if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC &&
+      !CGM.getLangOptions().ObjCAutoRefCount)
     return llvm::Constant::getNullValue(PtrTy);
 
   llvm::SmallVector<ObjCIvarDecl*, 32> Ivars;
   const ObjCInterfaceDecl *OI = OMD->getClassInterface();
-  CGM.getContext().DeepCollectObjCIvars(OI, true, Ivars);
+  if (CGM.getLangOptions().ObjCAutoRefCount)
+    CGM.getContext().ShallowCollectObjCIvars(OI, Ivars);
+  else
+    CGM.getContext().DeepCollectObjCIvars(OI, true, Ivars);
 
   llvm::SmallVector<FieldDecl*, 32> RecFields;
   for (unsigned k = 0, e = Ivars.size(); k != e; ++k)
@@ -4743,7 +4778,12 @@
   CLS_META = 0x1,
   CLS_ROOT = 0x2,
   OBJC2_CLS_HIDDEN = 0x10,
-  CLS_EXCEPTION = 0x20
+  CLS_EXCEPTION = 0x20,
+
+  /// (Obsolete) ARC-specific: this class has a .release_ivars method
+  CLS_HAS_IVAR_RELEASER = 0x40,
+  /// class was compiled with -fobjc-arr
+  CLS_COMPILED_BY_ARC = 0x80  // (1<<7)
 };
 /// BuildClassRoTInitializer - generate meta-data for:
 /// struct _class_ro_t {
@@ -4767,6 +4807,10 @@
   const ObjCImplementationDecl *ID) {
   std::string ClassName = ID->getNameAsString();
   std::vector<llvm::Constant*> Values(10); // 11 for 64bit targets!
+
+  if (CGM.getLangOptions().ObjCAutoRefCount)
+    flags |= CLS_COMPILED_BY_ARC;
+
   Values[ 0] = llvm::ConstantInt::get(ObjCTypes.IntTy, flags);
   Values[ 1] = llvm::ConstantInt::get(ObjCTypes.IntTy, InstanceStart);
   Values[ 2] = llvm::ConstantInt::get(ObjCTypes.IntTy, InstanceSize);
@@ -4936,7 +4980,7 @@
     ID->getClassInterface()->getVisibility() == HiddenVisibility;
   if (classIsHidden)
     flags |= OBJC2_CLS_HIDDEN;
-  if (ID->getNumIvarInitializers())
+  if (ID->hasCXXStructors())
     flags |= eClassFlags_ABI2_HasCXXStructors;
   if (!ID->getClassInterface()->getSuperClass()) {
     // class is root
@@ -4972,7 +5016,7 @@
   flags = CLS;
   if (classIsHidden)
     flags |= OBJC2_CLS_HIDDEN;
-  if (ID->getNumIvarInitializers())
+  if (ID->hasCXXStructors())
     flags |= eClassFlags_ABI2_HasCXXStructors;
 
   if (hasObjCExceptionAttribute(CGM.getContext(), ID->getClassInterface()))
@@ -5719,28 +5763,39 @@
   return GV;
 }
 
-llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CGBuilderTy &Builder,
-                                                  const ObjCInterfaceDecl *ID) {
-  llvm::GlobalVariable *&Entry = ClassReferences[ID->getIdentifier()];
-
+llvm::Value *CGObjCNonFragileABIMac::EmitClassRefFromId(CGBuilderTy &Builder,
+                                                        IdentifierInfo *II) {
+  llvm::GlobalVariable *&Entry = ClassReferences[II];
+  
   if (!Entry) {
-    std::string ClassName(getClassSymbolPrefix() + ID->getNameAsString());
+    std::string ClassName(getClassSymbolPrefix() + II->getName().str());
     llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName);
     Entry =
-      new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
-                               false, llvm::GlobalValue::InternalLinkage,
-                               ClassGV,
-                               "\01L_OBJC_CLASSLIST_REFERENCES_$_");
+    new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
+                             false, llvm::GlobalValue::InternalLinkage,
+                             ClassGV,
+                             "\01L_OBJC_CLASSLIST_REFERENCES_$_");
     Entry->setAlignment(
-      CGM.getTargetData().getABITypeAlignment(
-        ObjCTypes.ClassnfABIPtrTy));
+                        CGM.getTargetData().getABITypeAlignment(
+                                                                ObjCTypes.ClassnfABIPtrTy));
     Entry->setSection("__DATA, __objc_classrefs, regular, no_dead_strip");
     CGM.AddUsedGlobal(Entry);
   }
-
+  
   return Builder.CreateLoad(Entry, "tmp");
 }
 
+llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CGBuilderTy &Builder,
+                                                  const ObjCInterfaceDecl *ID) {
+  return EmitClassRefFromId(Builder, ID->getIdentifier());
+}
+
+llvm::Value *CGObjCNonFragileABIMac::EmitNSAutoreleasePoolClassRef(
+                                                    CGBuilderTy &Builder) {
+  IdentifierInfo *II = &CGM.getContext().Idents.get("NSAutoreleasePool");
+  return EmitClassRefFromId(Builder, II);
+}
+
 llvm::Value *
 CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder,
                                           const ObjCInterfaceDecl *ID) {

Modified: cfe/trunk/lib/CodeGen/CGObjCRuntime.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCRuntime.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjCRuntime.h (original)
+++ cfe/trunk/lib/CodeGen/CGObjCRuntime.h Wed Jun 15 18:02:42 2011
@@ -205,7 +205,13 @@
   /// interface decl.
   virtual llvm::Value *GetClass(CGBuilderTy &Builder,
                                 const ObjCInterfaceDecl *OID) = 0;
-
+  
+  
+  virtual llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder) {
+    assert(false &&"autoreleasepool unsupported in this ABI");
+    return 0;
+  }
+  
   /// EnumerationMutationFunction - Return the function that's called by the
   /// compiler when a mutation is detected during foreach iteration.
   virtual llvm::Constant *EnumerationMutationFunction() = 0;

Modified: cfe/trunk/lib/CodeGen/CGStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmt.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGStmt.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGStmt.cpp Wed Jun 15 18:02:42 2011
@@ -151,6 +151,9 @@
   case Stmt::ObjCForCollectionStmtClass:
     EmitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(*S));
     break;
+  case Stmt::ObjCAutoreleasePoolStmtClass:
+    EmitObjCAutoreleasePoolStmt(cast<ObjCAutoreleasePoolStmt>(*S));
+    break;
       
   case Stmt::CXXTryStmtClass:
     EmitCXXTryStmt(cast<CXXTryStmt>(*S));
@@ -764,7 +767,7 @@
   } else if (RV->getType()->isAnyComplexType()) {
     EmitComplexExprIntoAddr(RV, ReturnValue, false);
   } else {
-    EmitAggExpr(RV, AggValueSlot::forAddr(ReturnValue, false, true));
+    EmitAggExpr(RV, AggValueSlot::forAddr(ReturnValue, Qualifiers(), true));
   }
 
   EmitBranchThroughCleanup(ReturnBlock);

Modified: cfe/trunk/lib/CodeGen/CGValue.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGValue.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGValue.h (original)
+++ cfe/trunk/lib/CodeGen/CGValue.h Wed Jun 15 18:02:42 2011
@@ -101,8 +101,6 @@
 /// bitfields, this is not a simple LLVM pointer, it may be a pointer plus a
 /// bitrange.
 class LValue {
-  // FIXME: alignment?
-
   enum {
     Simple,       // This is a normal l-value, use getAddress().
     VectorElt,    // This is a vector element l-value (V[i]), use getVector*
@@ -318,9 +316,11 @@
 class AggValueSlot {
   /// The address.
   llvm::Value *Addr;
+
+  // Qualifiers
+  Qualifiers Quals;
   
   // Associated flags.
-  bool VolatileFlag : 1;
   bool LifetimeFlag : 1;
   bool RequiresGCollection : 1;
   
@@ -335,25 +335,31 @@
   static AggValueSlot ignored() {
     AggValueSlot AV;
     AV.Addr = 0;
-    AV.VolatileFlag = AV.LifetimeFlag = AV.RequiresGCollection = AV.IsZeroed =0;
+    AV.Quals = Qualifiers();
+    AV.LifetimeFlag = AV.RequiresGCollection = AV.IsZeroed =0;
     return AV;
   }
 
   /// forAddr - Make a slot for an aggregate value.
   ///
   /// \param Volatile - true if the slot should be volatile-initialized
+  ///
+  /// \param Qualifiers - The qualifiers that dictate how the slot
+  /// should be initialied. Only 'volatile' and the Objective-C
+  /// lifetime qualifiers matter.
+  ///
   /// \param LifetimeExternallyManaged - true if the slot's lifetime
   ///   is being externally managed; false if a destructor should be
   ///   registered for any temporaries evaluated into the slot
   /// \param RequiresGCollection - true if the slot is located
   ///   somewhere that ObjC GC calls should be emitted for
-  static AggValueSlot forAddr(llvm::Value *Addr, bool Volatile,
+  static AggValueSlot forAddr(llvm::Value *Addr, Qualifiers Quals,
                               bool LifetimeExternallyManaged,
                               bool RequiresGCollection = false,
                               bool IsZeroed = false) {
     AggValueSlot AV;
     AV.Addr = Addr;
-    AV.VolatileFlag = Volatile;
+    AV.Quals = Quals;
     AV.LifetimeFlag = LifetimeExternallyManaged;
     AV.RequiresGCollection = RequiresGCollection;
     AV.IsZeroed = IsZeroed;
@@ -362,7 +368,7 @@
 
   static AggValueSlot forLValue(LValue LV, bool LifetimeExternallyManaged,
                                 bool RequiresGCollection = false) {
-    return forAddr(LV.getAddress(), LV.isVolatileQualified(),
+    return forAddr(LV.getAddress(), LV.getQuals(),
                    LifetimeExternallyManaged, RequiresGCollection);
   }
 
@@ -373,8 +379,14 @@
     LifetimeFlag = Managed;
   }
 
+  Qualifiers getQualifiers() const { return Quals; }
+
   bool isVolatile() const {
-    return VolatileFlag;
+    return Quals.hasVolatile();
+  }
+
+  Qualifiers::ObjCLifetime getObjCLifetime() const {
+    return Quals.getObjCLifetime();
   }
 
   bool requiresGCollection() const {

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Wed Jun 15 18:02:42 2011
@@ -31,7 +31,7 @@
 CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
   : CodeGenTypeCache(cgm), CGM(cgm),
     Target(CGM.getContext().Target), Builder(cgm.getModule().getContext()),
-    BlockInfo(0), BlockPointer(0),
+    AutoreleaseResult(false), BlockInfo(0), BlockPointer(0),
     NormalCleanupDest(0), EHCleanupDest(0), NextCleanupDestIndex(1),
     ExceptionSlot(0), EHSelectorSlot(0),
     DebugInfo(0), DisableDebugInfo(false), DidCallStackSave(false),
@@ -142,6 +142,13 @@
   assert(BreakContinueStack.empty() &&
          "mismatched push/pop in break/continue stack!");
 
+  // Pop any cleanups that might have been associated with the
+  // parameters.  Do this in whatever block we're currently in; it's
+  // important to do this before we enter the return block or return
+  // edges will be *really* confused.
+  if (EHStack.stable_begin() != PrologueCleanupDepth)
+    PopCleanupBlocks(PrologueCleanupDepth);
+
   // Emit function epilog (to return).
   EmitReturnBlock();
 
@@ -311,9 +318,19 @@
     ReturnValue = CurFn->arg_begin();
   } else {
     ReturnValue = CreateIRTemp(RetTy, "retval");
+
+    // Tell the epilog emitter to autorelease the result.  We do this
+    // now so that various specialized functions can suppress it
+    // during their IR-generation.
+    if (getLangOptions().ObjCAutoRefCount &&
+        !CurFnInfo->isReturnsRetained() &&
+        RetTy->isObjCRetainableType())
+      AutoreleaseResult = true;
   }
 
   EmitStartEHSpec(CurCodeDecl);
+
+  PrologueCleanupDepth = EHStack.stable_begin();
   EmitFunctionProlog(*CurFnInfo, CurFn, Args);
 
   if (D && isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance())

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Wed Jun 15 18:02:42 2011
@@ -18,6 +18,7 @@
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/AST/CharUnits.h"
+#include "clang/Frontend/CodeGenOptions.h"
 #include "clang/Basic/ABI.h"
 #include "clang/Basic/TargetInfo.h"
 #include "llvm/ADT/DenseMap.h"
@@ -63,6 +64,7 @@
   class ObjCAtTryStmt;
   class ObjCAtThrowStmt;
   class ObjCAtSynchronizedStmt;
+  class ObjCAutoreleasePoolStmt;
 
 namespace CodeGen {
   class CodeGenTypes;
@@ -568,6 +570,10 @@
   /// CurGD - The GlobalDecl for the current function being compiled.
   GlobalDecl CurGD;
 
+  /// PrologueCleanupDepth - The cleanup depth enclosing all the
+  /// cleanups associated with the parameters.
+  EHScopeStack::stable_iterator PrologueCleanupDepth;
+
   /// ReturnBlock - Unified return block.
   JumpDest ReturnBlock;
 
@@ -584,6 +590,9 @@
 
   bool CatchUndefined;
 
+  /// In ARC, whether we should autorelease the return value.
+  bool AutoreleaseResult;
+
   const CodeGen::CGBlockInfo *BlockInfo;
   llvm::Value *BlockPointer;
 
@@ -1048,6 +1057,9 @@
   void disableDebugInfo() { DisableDebugInfo = true; }
   void enableDebugInfo() { DisableDebugInfo = false; }
 
+  bool shouldUseFusedARCCalls() {
+    return CGM.getCodeGenOpts().OptimizationLevel == 0;
+  }
 
   const LangOptions &getLangOptions() const { return CGM.getLangOptions(); }
 
@@ -1345,7 +1357,8 @@
   /// CreateAggTemp - Create a temporary memory object for the given
   /// aggregate type.
   AggValueSlot CreateAggTemp(QualType T, const llvm::Twine &Name = "tmp") {
-    return AggValueSlot::forAddr(CreateMemTemp(T, Name), false, false);
+    return AggValueSlot::forAddr(CreateMemTemp(T, Name), T.getQualifiers(),
+                                 false);
   }
 
   /// Emit a cast to void* in the appropriate address space.
@@ -1379,12 +1392,11 @@
   /// EmitAnyExprToMem - Emits the code necessary to evaluate an
   /// arbitrary expression into the given memory location.
   void EmitAnyExprToMem(const Expr *E, llvm::Value *Location,
-                        bool IsLocationVolatile,
-                        bool IsInitializer);
+                        Qualifiers Quals, bool IsInitializer);
 
   /// EmitExprAsInit - Emits the code necessary to initialize a
   /// location in memory with the given initializer.
-  void EmitExprAsInit(const Expr *init, const VarDecl *var,
+  void EmitExprAsInit(const Expr *init, const ValueDecl *D,
                       llvm::Value *loc, CharUnits alignment,
                       bool capturedByInit);
 
@@ -1584,6 +1596,10 @@
   /// This function can be called with a null (unreachable) insert point.
   void EmitVarDecl(const VarDecl &D);
 
+  void EmitScalarInit(const Expr *init, const ValueDecl *D,
+                      llvm::Value *addr, bool capturedByInit,
+                      bool isVolatile, unsigned alignment, QualType type);
+
   typedef void SpecialInitFn(CodeGenFunction &Init, const VarDecl &D,
                              llvm::Value *Address);
 
@@ -1709,6 +1725,7 @@
   void EmitObjCAtTryStmt(const ObjCAtTryStmt &S);
   void EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S);
   void EmitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt &S);
+  void EmitObjCAutoreleasePoolStmt(const ObjCAutoreleasePoolStmt &S);
 
   llvm::Constant *getUnwindResumeFn();
   llvm::Constant *getUnwindResumeOrRethrowFn();
@@ -1961,6 +1978,64 @@
   RValue EmitObjCMessageExpr(const ObjCMessageExpr *E,
                              ReturnValueSlot Return = ReturnValueSlot());
 
+  /// Retrieves the default cleanup kind for an ARC cleanup.
+  /// Except under -fobjc-arc-eh, ARC cleanups are normal-only.
+  CleanupKind getARCCleanupKind() {
+    return CGM.getCodeGenOpts().ObjCAutoRefCountExceptions
+             ? NormalAndEHCleanup : NormalCleanup;
+  }
+
+  // ARC primitives.
+  void EmitARCInitWeak(llvm::Value *value, llvm::Value *addr);
+  void EmitARCDestroyWeak(llvm::Value *addr);
+  llvm::Value *EmitARCLoadWeak(llvm::Value *addr);
+  llvm::Value *EmitARCLoadWeakRetained(llvm::Value *addr);
+  llvm::Value *EmitARCStoreWeak(llvm::Value *value, llvm::Value *addr,
+                                bool ignored);
+  void EmitARCCopyWeak(llvm::Value *dst, llvm::Value *src);
+  void EmitARCMoveWeak(llvm::Value *dst, llvm::Value *src);
+  llvm::Value *EmitARCRetainAutorelease(QualType type, llvm::Value *value);
+  llvm::Value *EmitARCRetainAutoreleaseNonBlock(llvm::Value *value);
+  llvm::Value *EmitARCStoreStrong(LValue addr, QualType type,
+                                  llvm::Value *value, bool ignored);
+  llvm::Value *EmitARCStoreStrongCall(llvm::Value *addr, llvm::Value *value,
+                                      bool ignored);
+  llvm::Value *EmitARCRetain(QualType type, llvm::Value *value);
+  llvm::Value *EmitARCRetainNonBlock(llvm::Value *value);
+  llvm::Value *EmitARCRetainBlock(llvm::Value *value);
+  void EmitARCRelease(llvm::Value *value, bool precise);
+  llvm::Value *EmitARCAutorelease(llvm::Value *value);
+  llvm::Value *EmitARCAutoreleaseReturnValue(llvm::Value *value);
+  llvm::Value *EmitARCRetainAutoreleaseReturnValue(llvm::Value *value);
+  llvm::Value *EmitARCRetainAutoreleasedReturnValue(llvm::Value *value);
+
+  std::pair<LValue,llvm::Value*>
+  EmitARCStoreAutoreleasing(const BinaryOperator *e);
+  std::pair<LValue,llvm::Value*>
+  EmitARCStoreStrong(const BinaryOperator *e, bool ignored);
+
+  llvm::Value *EmitObjCProduceObject(QualType T, llvm::Value *Ptr);
+  llvm::Value *EmitObjCConsumeObject(QualType T, llvm::Value *Ptr);
+  llvm::Value *EmitObjCExtendObjectLifetime(QualType T, llvm::Value *Ptr);
+
+  llvm::Value *EmitARCRetainScalarExpr(const Expr *expr);
+  llvm::Value *EmitARCRetainAutoreleaseScalarExpr(const Expr *expr);
+
+  void PushARCReleaseCleanup(CleanupKind kind, QualType type,
+                             llvm::Value *addr, bool precise);
+  void PushARCWeakReleaseCleanup(CleanupKind kind, QualType type,
+                                 llvm::Value *addr);
+  void PushARCFieldReleaseCleanup(CleanupKind cleanupKind,
+                                  const FieldDecl *Field);
+  void PushARCFieldWeakReleaseCleanup(CleanupKind cleanupKind,
+                                      const FieldDecl *Field);
+
+  void EmitObjCAutoreleasePoolPop(llvm::Value *Ptr); 
+  llvm::Value *EmitObjCAutoreleasePoolPush();
+  llvm::Value *EmitObjCMRRAutoreleasePoolPush();
+  void EmitObjCAutoreleasePoolCleanup(llvm::Value *Ptr);
+  void EmitObjCMRRAutoreleasePoolPop(llvm::Value *Ptr); 
+
   /// EmitReferenceBindingToExpr - Emits a reference binding to the passed in
   /// expression. Will emit a temporary variable if E is not an LValue.
   RValue EmitReferenceBindingToExpr(const Expr* E,

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Wed Jun 15 18:02:42 2011
@@ -64,7 +64,7 @@
     ABI(createCXXABI(*this)), 
     Types(C, M, TD, getTargetCodeGenInfo().getABIInfo(), ABI),
     TBAA(0),
-    VTables(*this), Runtime(0), DebugInfo(0),
+    VTables(*this), Runtime(0), DebugInfo(0), ARCData(0), RRData(0),
     CFConstantStringClassRef(0), ConstantStringClassRef(0),
     VMContext(M.getContext()),
     NSConcreteGlobalBlockDecl(0), NSConcreteStackBlockDecl(0),
@@ -88,6 +88,10 @@
 
   Block.GlobalUniqueCount = 0;
 
+  if (C.getLangOptions().ObjCAutoRefCount)
+    ARCData = new ARCEntrypoints();
+  RRData = new RREntrypoints();
+
   // Initialize the type cache.
   llvm::LLVMContext &LLVMContext = M.getContext();
   VoidTy = llvm::Type::getVoidTy(LLVMContext);
@@ -108,6 +112,8 @@
   delete &ABI;
   delete TBAA;
   delete DebugInfo;
+  delete ARCData;
+  delete RRData;
 }
 
 void CodeGenModule::createObjCRuntime() {
@@ -830,7 +836,8 @@
 llvm::Constant *
 CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName,
                                        const llvm::Type *Ty,
-                                       GlobalDecl D, bool ForVTable) {
+                                       GlobalDecl D, bool ForVTable,
+                                       llvm::Attributes ExtraAttrs) {
   // Lookup the entry, lazily creating it if necessary.
   llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
   if (Entry) {
@@ -869,6 +876,8 @@
   assert(F->getName() == MangledName && "name was uniqued!");
   if (D.getDecl())
     SetFunctionAttributes(D, F, IsIncompleteFunction);
+  if (ExtraAttrs != llvm::Attribute::None)
+    F->addFnAttr(ExtraAttrs);
 
   // This is the first use or definition of a mangled name.  If there is a
   // deferred decl with this name, remember that we need to emit it at the end
@@ -937,8 +946,10 @@
 /// type and name.
 llvm::Constant *
 CodeGenModule::CreateRuntimeFunction(const llvm::FunctionType *FTy,
-                                     llvm::StringRef Name) {
-  return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false);
+                                     llvm::StringRef Name,
+                                     llvm::Attributes ExtraAttrs) {
+  return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false,
+                                 ExtraAttrs);
 }
 
 static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D,
@@ -1997,6 +2008,7 @@
                              false, true, false, ObjCMethodDecl::Required);
     D->addInstanceMethod(DTORMethod);
     CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false);
+    D->setHasCXXStructors(true);
   }
 
   // If the implementation doesn't have any ivar initializers, we don't need
@@ -2015,6 +2027,7 @@
                                                 ObjCMethodDecl::Required);
   D->addInstanceMethod(CTORMethod);
   CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true);
+  D->setHasCXXStructors(true);
 }
 
 /// EmitNamespace - Emit all declarations in a namespace.

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.h Wed Jun 15 18:02:42 2011
@@ -131,6 +131,71 @@
     /// The alignment of a pointer into the generic address space.
     unsigned char PointerAlignInBytes;
   };
+
+struct RREntrypoints {
+  RREntrypoints() { memset(this, 0, sizeof(*this)); }
+  /// void objc_autoreleasePoolPop(void*);
+  llvm::Constant *objc_autoreleasePoolPop;
+
+  /// void *objc_autoreleasePoolPush(void);
+  llvm::Constant *objc_autoreleasePoolPush;
+};
+
+struct ARCEntrypoints {
+  ARCEntrypoints() { memset(this, 0, sizeof(*this)); }
+
+  /// id objc_autorelease(id);
+  llvm::Constant *objc_autorelease;
+
+  /// id objc_autoreleaseReturnValue(id);
+  llvm::Constant *objc_autoreleaseReturnValue;
+
+  /// void objc_copyWeak(id *dest, id *src);
+  llvm::Constant *objc_copyWeak;
+
+  /// void objc_destroyWeak(id*);
+  llvm::Constant *objc_destroyWeak;
+
+  /// id objc_initWeak(id*, id);
+  llvm::Constant *objc_initWeak;
+
+  /// id objc_loadWeak(id*);
+  llvm::Constant *objc_loadWeak;
+
+  /// id objc_loadWeakRetained(id*);
+  llvm::Constant *objc_loadWeakRetained;
+
+  /// void objc_moveWeak(id *dest, id *src);
+  llvm::Constant *objc_moveWeak;
+
+  /// id objc_retain(id);
+  llvm::Constant *objc_retain;
+
+  /// id objc_retainAutorelease(id);
+  llvm::Constant *objc_retainAutorelease;
+
+  /// id objc_retainAutoreleaseReturnValue(id);
+  llvm::Constant *objc_retainAutoreleaseReturnValue;
+
+  /// id objc_retainAutoreleasedReturnValue(id);
+  llvm::Constant *objc_retainAutoreleasedReturnValue;
+
+  /// id objc_retainBlock(id);
+  llvm::Constant *objc_retainBlock;
+
+  /// void objc_release(id);
+  llvm::Constant *objc_release;
+
+  /// id objc_storeStrong(id*, id);
+  llvm::Constant *objc_storeStrong;
+
+  /// id objc_storeWeak(id*, id);
+  llvm::Constant *objc_storeWeak;
+
+  /// A void(void) inline asm to use to mark that the return value of
+  /// a call will be immediately retain.
+  llvm::InlineAsm *retainAutoreleasedReturnValueMarker;
+};
   
 /// CodeGenModule - This class organizes the cross-function state that is used
 /// while generating LLVM code.
@@ -157,6 +222,8 @@
 
   CGObjCRuntime* Runtime;
   CGDebugInfo* DebugInfo;
+  ARCEntrypoints *ARCData;
+  RREntrypoints *RRData;
 
   // WeakRefReferences - A set of references that have only been seen via
   // a weakref so far. This is used to remove the weak of the reference if we ever
@@ -275,6 +342,16 @@
   /// getCXXABI() - Return a reference to the configured C++ ABI.
   CGCXXABI &getCXXABI() { return ABI; }
 
+  ARCEntrypoints &getARCEntrypoints() const {
+    assert(getLangOptions().ObjCAutoRefCount && ARCData != 0);
+    return *ARCData;
+  }
+
+  RREntrypoints &getRREntrypoints() const {
+    assert(RRData != 0);
+    return *RRData;
+  }
+
   llvm::Value *getStaticLocalDeclAddress(const VarDecl *VD) {
     return StaticLocalDeclMap[VD];
   }
@@ -474,7 +551,7 @@
   /// created).
   llvm::Constant *GetAddrOfConstantCString(const std::string &str,
                                            const char *GlobalName=0);
-
+  
   /// GetAddrOfCXXConstructor - Return the address of the constructor of the
   /// given type.
   llvm::GlobalValue *GetAddrOfCXXConstructor(const CXXConstructorDecl *ctor,
@@ -514,7 +591,9 @@
   /// CreateRuntimeFunction - Create a new runtime function with the specified
   /// type and name.
   llvm::Constant *CreateRuntimeFunction(const llvm::FunctionType *Ty,
-                                        llvm::StringRef Name);
+                                        llvm::StringRef Name,
+                                        llvm::Attributes ExtraAttrs =
+                                          llvm::Attribute::None);
   /// CreateRuntimeVariable - Create a new runtime global variable with the
   /// specified type and name.
   llvm::Constant *CreateRuntimeVariable(const llvm::Type *Ty,
@@ -642,7 +721,9 @@
   llvm::Constant *GetOrCreateLLVMFunction(llvm::StringRef MangledName,
                                           const llvm::Type *Ty,
                                           GlobalDecl D,
-                                          bool ForVTable);
+                                          bool ForVTable,
+                                          llvm::Attributes ExtraAttrs =
+                                            llvm::Attribute::None);
   llvm::Constant *GetOrCreateLLVMGlobal(llvm::StringRef MangledName,
                                         const llvm::PointerType *PTy,
                                         const VarDecl *D,

Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Wed Jun 15 18:02:42 2011
@@ -802,10 +802,27 @@
   if (expr->doesUsualArrayDeleteWantSize())
     return true;
 
+  // Automatic Reference Counting:
+  //   We need an array cookie for pointers with strong or weak lifetime.
+  QualType AllocatedType = expr->getAllocatedType();
+  if (getContext().getLangOptions().ObjCAutoRefCount &&
+      AllocatedType->isObjCLifetimeType()) {
+    switch (AllocatedType.getObjCLifetime()) {
+    case Qualifiers::OCL_None:
+    case Qualifiers::OCL_ExplicitNone:
+    case Qualifiers::OCL_Autoreleasing:
+      return false;
+      
+    case Qualifiers::OCL_Strong:
+    case Qualifiers::OCL_Weak:
+      return true;
+    }
+  }
+
   // Otherwise, if the class has a non-trivial destructor, it always
   // needs a cookie.
   const CXXRecordDecl *record =
-    expr->getAllocatedType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
+    AllocatedType->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
   return (record && !record->hasTrivialDestructor());
 }
 
@@ -816,6 +833,22 @@
   if (expr->doesUsualArrayDeleteWantSize())
     return true;
 
+  // Automatic Reference Counting:
+  //   We need an array cookie for pointers with strong or weak lifetime.
+  if (getContext().getLangOptions().ObjCAutoRefCount &&
+      elementType->isObjCLifetimeType()) {
+    switch (elementType.getObjCLifetime()) {
+    case Qualifiers::OCL_None:
+    case Qualifiers::OCL_ExplicitNone:
+    case Qualifiers::OCL_Autoreleasing:
+      return false;
+
+    case Qualifiers::OCL_Strong:
+    case Qualifiers::OCL_Weak:
+      return true;
+    }
+  }
+  
   // Otherwise, if the class has a non-trivial destructor, it always
   // needs a cookie.
   const CXXRecordDecl *record =

Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original)
+++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Wed Jun 15 18:02:42 2011
@@ -2277,6 +2277,10 @@
     return 13;
   }
 
+  llvm::StringRef getARCRetainAutoreleasedReturnValueMarker() const {
+    return "mov\tr7, r7\t\t@ marker for objc_retainAutoreleaseReturnValue";
+  }
+
   bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
                                llvm::Value *Address) const {
     CodeGen::CGBuilderTy &Builder = CGF.Builder;
@@ -2290,8 +2294,6 @@
 
     return false;
   }
-
-
 };
 
 }

Modified: cfe/trunk/lib/CodeGen/TargetInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/TargetInfo.h (original)
+++ cfe/trunk/lib/CodeGen/TargetInfo.h Wed Jun 15 18:02:42 2011
@@ -111,6 +111,20 @@
                                                   const llvm::Type* Ty) const {
       return Ty;
     }
+
+    /// Retrieve the address of a function to call immediately before
+    /// calling objc_retainAutoreleasedReturnValue.  The
+    /// implementation of objc_autoreleaseReturnValue sniffs the
+    /// instruction stream following its return address to decide
+    /// whether it's a call to objc_retainAutoreleasedReturnValue.
+    /// This can be prohibitively expensive, depending on the
+    /// relocation model, and so on some targets it instead sniffs for
+    /// a particular instruction sequence.  This functions returns
+    /// that instruction sequence in inline assembly, which will be
+    /// empty if none is required.
+    virtual llvm::StringRef getARCRetainAutoreleasedReturnValueMarker() const {
+      return "";
+    }
   };
 }
 

Modified: cfe/trunk/lib/Driver/ToolChain.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/ToolChain.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/ToolChain.cpp (original)
+++ cfe/trunk/lib/Driver/ToolChain.cpp Wed Jun 15 18:02:42 2011
@@ -201,7 +201,8 @@
 }
 
 void ToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args,
-                                             ArgStringList &CmdArgs) const {
+                                             ArgStringList &CmdArgs,
+                                             bool ObjCXXAutoRefCount) const {
   CXXStdlibType Type = GetCXXStdlibType(Args);
 
   switch (Type) {
@@ -209,10 +210,16 @@
     CmdArgs.push_back("-nostdinc++");
     CmdArgs.push_back("-cxx-isystem");
     CmdArgs.push_back("/usr/include/c++/v1");
+      
+    if (ObjCXXAutoRefCount)
+      CmdArgs.push_back("-fobjc-arc-cxxlib=libc++");
     break;
 
   case ToolChain::CST_Libstdcxx:
     // Currently handled by the mass of goop in InitHeaderSearch.
+
+    if (ObjCXXAutoRefCount)
+      CmdArgs.push_back("-fobjc-arc-cxxlib=libstdc++");
     break;
   }
 }

Modified: cfe/trunk/lib/Driver/ToolChains.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/ToolChains.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/ToolChains.cpp (original)
+++ cfe/trunk/lib/Driver/ToolChains.cpp Wed Jun 15 18:02:42 2011
@@ -26,6 +26,7 @@
 
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/MemoryBuffer.h"
@@ -41,7 +42,8 @@
 /// Darwin - Darwin tool chain for i386 and x86_64.
 
 Darwin::Darwin(const HostInfo &Host, const llvm::Triple& Triple)
-  : ToolChain(Host, Triple), TargetInitialized(false)
+  : ToolChain(Host, Triple), TargetInitialized(false),
+    ARCRuntimeForSimulator(ARCSimulator_None)
 {
   // Compute the initial Darwin version based on the host.
   bool HadExtra;
@@ -70,6 +72,25 @@
   return true;
 }
 
+/// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0.
+bool Darwin::HasARCRuntime() const {
+  // FIXME: Remove this once there is a proper way to detect an ARC runtime
+  // for the simulator.
+  switch (ARCRuntimeForSimulator) {
+  case ARCSimulator_None:
+    break;
+  case ARCSimulator_HasARCRuntime:
+    return true;
+  case ARCSimulator_NoARCRuntime:
+    return false;
+  }
+
+  if (isTargetIPhoneOS())
+    return !isIPhoneOSVersionLT(5);
+  else
+    return !isMacosxVersionLT(10, 7);
+}
+
 // FIXME: Can we tablegen this?
 static const char *GetArmArchForMArch(llvm::StringRef Value) {
   if (Value == "armv6k")
@@ -320,6 +341,30 @@
     CmdArgs.push_back(Args.MakeArgString("-L" + P.str()));
 }
 
+void DarwinClang::AddLinkARCArgs(const ArgList &Args,
+                                 ArgStringList &CmdArgs) const {
+  
+  CmdArgs.push_back("-force_load");    
+  llvm::sys::Path P(getDriver().ClangExecutable);
+  P.eraseComponent(); // 'clang'
+  P.eraseComponent(); // 'bin'
+  P.appendComponent("lib");
+  P.appendComponent("arc");
+  P.appendComponent("libarclite_");
+  std::string s = P.str();
+  // Mash in the platform.
+  if (isTargetIPhoneOS())
+    s += "iphoneos";
+  // FIXME: isTargetIphoneOSSimulator() is not returning true.
+  else if (ARCRuntimeForSimulator != ARCSimulator_None)
+    s += "iphonesimulator";
+  else
+    s += "macosx";
+  s += ".a";
+
+  CmdArgs.push_back(Args.MakeArgString(s));
+}
+
 void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
                                         ArgStringList &CmdArgs) const {
   // Darwin doesn't support real static executables, don't link any runtime
@@ -389,6 +434,35 @@
   }
 }
 
+static inline llvm::StringRef SimulatorVersionDefineName() {
+  return "__IPHONE_OS_VERSION_MIN_REQUIRED";
+}
+
+/// \brief Parse the simulator version define:
+/// __IPHONE_OS_VERSION_MIN_REQUIRED=([0-9])([0-9][0-9])([0-9][0-9])
+// and return the grouped values as integers, e.g:
+//   __IPHONE_OS_VERSION_MIN_REQUIRED=40201
+// will return Major=4, Minor=2, Micro=1.
+static bool GetVersionFromSimulatorDefine(llvm::StringRef define,
+                                          unsigned &Major, unsigned &Minor,
+                                          unsigned &Micro) {
+  assert(define.startswith(SimulatorVersionDefineName()));
+  llvm::StringRef name, version;
+  llvm::tie(name, version) = define.split('=');
+  if (version.empty())
+    return false;
+  std::string verstr = version.str();
+  char *end;
+  unsigned num = (unsigned) strtol(verstr.c_str(), &end, 10);
+  if (*end != '\0')
+    return false;
+  Major = num / 10000;
+  num = num % 10000;
+  Minor = num / 100;
+  Micro = num % 100;
+  return true;
+}
+
 void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
   const OptTable &Opts = getDriver().getOpts();
 
@@ -396,6 +470,27 @@
   Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ);
   Arg *iOSSimVersion = Args.getLastArg(
     options::OPT_mios_simulator_version_min_EQ);
+
+  // FIXME: HACK! When compiling for the simulator we don't get a
+  // '-miphoneos-version-min' to help us know whether there is an ARC runtime
+  // or not; try to parse a __IPHONE_OS_VERSION_MIN_REQUIRED
+  // define passed in command-line.
+  if (!iOSVersion) {
+    for (arg_iterator it = Args.filtered_begin(options::OPT_D),
+           ie = Args.filtered_end(); it != ie; ++it) {
+      llvm::StringRef define = (*it)->getValue(Args);
+      if (define.startswith(SimulatorVersionDefineName())) {
+        unsigned Major, Minor, Micro;
+        if (GetVersionFromSimulatorDefine(define, Major, Minor, Micro) &&
+            Major < 10 && Minor < 100 && Micro < 100) {
+          ARCRuntimeForSimulator = Major < 5 ? ARCSimulator_NoARCRuntime
+                                             : ARCSimulator_HasARCRuntime;
+        }
+        break;
+      }
+    }
+  }
+
   if (OSXVersion && (iOSVersion || iOSSimVersion)) {
     getDriver().Diag(clang::diag::err_drv_argument_not_allowed_with)
           << OSXVersion->getAsString(Args)

Modified: cfe/trunk/lib/Driver/ToolChains.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/ToolChains.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/ToolChains.h (original)
+++ cfe/trunk/lib/Driver/ToolChains.h Wed Jun 15 18:02:42 2011
@@ -57,6 +57,16 @@
   // the argument translation business.
   mutable bool TargetInitialized;
 
+  // FIXME: Remove this once there is a proper way to detect an ARC runtime
+  // for the simulator.
+ public:
+  mutable enum {
+    ARCSimulator_None,
+    ARCSimulator_HasARCRuntime,
+    ARCSimulator_NoARCRuntime
+  } ARCRuntimeForSimulator;
+
+private:
   /// Whether we are targeting iPhoneOS target.
   mutable bool TargetIsIPhoneOS;
 
@@ -157,6 +167,10 @@
   virtual void AddLinkSearchPathArgs(const ArgList &Args,
                                      ArgStringList &CmdArgs) const = 0;
 
+  /// AddLinkARCArgs - Add the linker arguments to link the ARC runtime library.
+  virtual void AddLinkARCArgs(const ArgList &Args,
+                              ArgStringList &CmdArgs) const = 0;
+  
   /// AddLinkRuntimeLibArgs - Add the linker arguments to link the compiler
   /// runtime library.
   virtual void AddLinkRuntimeLibArgs(const ArgList &Args,
@@ -170,6 +184,8 @@
 
   virtual bool HasNativeLLVMSupport() const;
 
+  virtual bool HasARCRuntime() const;
+
   virtual DerivedArgList *TranslateArgs(const DerivedArgList &Args,
                                         const char *BoundArch) const;
 
@@ -257,6 +273,8 @@
   virtual void AddCCKextLibArgs(const ArgList &Args,
                                 ArgStringList &CmdArgs) const;
 
+  virtual void AddLinkARCArgs(const ArgList &Args,
+                              ArgStringList &CmdArgs) const;
   /// }
 };
 

Modified: cfe/trunk/lib/Driver/Tools.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/Tools.cpp (original)
+++ cfe/trunk/lib/Driver/Tools.cpp Wed Jun 15 18:02:42 2011
@@ -30,6 +30,7 @@
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/Host.h"
 #include "llvm/Support/Process.h"
+#include "llvm/Support/ErrorHandling.h"
 
 #include "InputInfo.h"
 #include "ToolChains.h"
@@ -147,6 +148,12 @@
   }
 }
 
+/// \brief Determine whether Objective-C automated reference counting is
+/// enabled.
+static bool isObjCAutoRefCount(const ArgList &Args) {
+  return Args.hasFlag(options::OPT_fobjc_arc, options::OPT_fno_objc_arc, false);
+}
+
 static void addProfileRT(const ToolChain &TC, const ArgList &Args,
                          ArgStringList &CmdArgs) {
   if (Args.hasArg(options::OPT_fprofile_arcs) ||
@@ -318,8 +325,12 @@
 
   // Add C++ include arguments, if needed.
   types::ID InputType = Inputs[0].getType();
-  if (types::isCXX(InputType))
-    getToolChain().AddClangCXXStdlibIncludeArgs(Args, CmdArgs);
+  if (types::isCXX(InputType)) {
+    bool ObjCXXAutoRefCount
+      = types::isObjC(InputType) && isObjCAutoRefCount(Args);
+    getToolChain().AddClangCXXStdlibIncludeArgs(Args, CmdArgs, 
+                                                ObjCXXAutoRefCount);
+  }
 
   // Add -Wp, and -Xassembler if using the preprocessor.
 
@@ -1542,6 +1553,24 @@
                     options::OPT_fno_lax_vector_conversions))
     CmdArgs.push_back("-fno-lax-vector-conversions");
 
+  // Allow -fno-objc-arr to trump -fobjc-arr/-fobjc-arc.
+  // NOTE: This logic is duplicated in ToolChains.cpp.
+  bool ARC = isObjCAutoRefCount(Args);
+  if (ARC) {
+    CmdArgs.push_back("-fobjc-arc");
+
+    // Certain deployment targets don't have runtime support.
+    if (!getToolChain().HasARCRuntime())
+      CmdArgs.push_back("-fobjc-no-arc-runtime");
+
+    // Allow the user to enable full exceptions code emission.
+    // We define off for Objective-CC, on for Objective-C++.
+    if (Args.hasFlag(options::OPT_fobjc_arc_exceptions,
+                     options::OPT_fno_objc_arc_exceptions,
+                     /*default*/ types::isCXX(InputType)))
+      CmdArgs.push_back("-fobjc-arc-exceptions");
+  }
+
   // -fobjc-infer-related-result-type is the default, except in the Objective-C
   // rewriter.
   if (IsRewriter)
@@ -1553,7 +1582,10 @@
   if (!GCArg)
     GCArg = Args.getLastArg(options::OPT_fobjc_gc);
   if (GCArg) {
-    if (getToolChain().SupportsObjCGC()) {
+    if (ARC) {
+      D.Diag(clang::diag::err_drv_objc_gc_arr)
+        << GCArg->getAsString(Args);
+    } else if (getToolChain().SupportsObjCGC()) {
       GCArg->render(Args, CmdArgs);
     } else {
       // FIXME: We should move this to a hard error.
@@ -3141,6 +3173,12 @@
 
   getDarwinToolChain().AddLinkSearchPathArgs(Args, CmdArgs);
 
+  // In ARC, if we don't have runtime support, link in the runtime
+  // stubs.  We have to do this *before* adding any of the normal
+  // linker inputs so that its initializer gets run first.
+  if (!getDarwinToolChain().HasARCRuntime() && isObjCAutoRefCount(Args))
+    getDarwinToolChain().AddLinkARCArgs(Args, CmdArgs);
+
   AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
 
   if (LinkingOutput) {

Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Wed Jun 15 18:02:42 2011
@@ -169,6 +169,8 @@
     Res.push_back("-fno-use-cxa-atexit");
   if (Opts.CXXCtorDtorAliases)
     Res.push_back("-mconstructor-aliases");
+  if (Opts.ObjCAutoRefCountExceptions)
+    Res.push_back("-fobjc-arc-eh");
   if (!Opts.DebugPass.empty()) {
     Res.push_back("-mdebug-pass");
     Res.push_back(Opts.DebugPass);
@@ -670,6 +672,10 @@
       Res.push_back("-fobjc-gc-only");
     }
   }
+  if (Opts.ObjCAutoRefCount)
+    Res.push_back("-fobjc-arc");
+  if (Opts.ObjCNoAutoRefCountRuntime)
+    Res.push_back("-fobjc-no-arc-runtime");
   if (!Opts.ObjCInferRelatedResultType)
     Res.push_back("-fno-objc-infer-related-result-type");
   
@@ -951,6 +957,7 @@
                      (Opts.OptimizationLevel > 1 && !Opts.OptimizeSize);
 
   Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose);
+  Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions);
   Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit);
   Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases);
   Opts.CodeModel = Args.getLastArgValue(OPT_mcode_model);
@@ -1480,17 +1487,26 @@
   if (Args.hasArg(OPT_fno_operator_names))
     Opts.CXXOperatorNames = 0;
 
+  if (Opts.ObjC1) {
+    if (Args.hasArg(OPT_fobjc_gc_only))
+      Opts.setGCMode(LangOptions::GCOnly);
+    else if (Args.hasArg(OPT_fobjc_gc))
+      Opts.setGCMode(LangOptions::HybridGC);
+    else if (Args.hasArg(OPT_fobjc_arc)) {
+      Opts.ObjCAutoRefCount = 1;
+      if (!Args.hasArg(OPT_fobjc_nonfragile_abi))
+        Diags.Report(diag::err_arc_nonfragile_abi);
+      if (Args.hasArg(OPT_fobjc_no_arc_runtime))
+        Opts.ObjCNoAutoRefCountRuntime = 1;
+    }
+
+    if (Args.hasArg(OPT_fno_objc_infer_related_result_type))
+      Opts.ObjCInferRelatedResultType = 0;
+  }
+    
   if (Args.hasArg(OPT_fgnu89_inline))
     Opts.GNUInline = 1;
 
-  if (Args.hasArg(OPT_fobjc_gc_only))
-    Opts.setGCMode(LangOptions::GCOnly);
-  else if (Args.hasArg(OPT_fobjc_gc))
-    Opts.setGCMode(LangOptions::HybridGC);
-  
-  if (Args.hasArg(OPT_fno_objc_infer_related_result_type))
-    Opts.ObjCInferRelatedResultType = 0;
-  
   if (Args.hasArg(OPT_fapple_kext)) {
     if (!Opts.CPlusPlus)
       Diags.Report(diag::warn_c_kext);
@@ -1715,6 +1731,19 @@
 
     Opts.addRemappedFile(Split.first, Split.second);
   }
+  
+  if (Arg *A = Args.getLastArg(OPT_fobjc_arc_cxxlib_EQ)) {
+    llvm::StringRef Name = A->getValue(Args);
+    unsigned Library = llvm::StringSwitch<unsigned>(Name)
+      .Case("libc++", ARCXX_libcxx)
+      .Case("libstdc++", ARCXX_libstdcxx)
+      .Case("none", ARCXX_nolib)
+      .Default(~0U);
+    if (Library == ~0U)
+      Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
+    else
+      Opts.ObjCXXARCStandardLibrary = (ObjCXXARCStandardLibraryKind)Library;
+  }
 }
 
 static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,

Modified: cfe/trunk/lib/Frontend/InitPreprocessor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/InitPreprocessor.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/InitPreprocessor.cpp (original)
+++ cfe/trunk/lib/Frontend/InitPreprocessor.cpp Wed Jun 15 18:02:42 2011
@@ -221,6 +221,125 @@
                         ConstSuffix);
 }
 
+/// \brief Add definitions required for a smooth interaction between
+/// Objective-C++ automatic reference counting and libc++.
+static void AddObjCXXARCLibcxxDefines(const LangOptions &LangOpts, 
+                                      MacroBuilder &Builder) {
+  Builder.defineMacro("_LIBCPP_PREDEFINED_OBJC_ARC_ADDRESSOF");
+  
+  std::string Result;
+  {
+    // Provide overloads of the function std::__1::addressof() that accept
+    // references to lifetime-qualified objects. libc++'s (more general)
+    // std::__1::addressof() template fails to instantiate with such types,
+    // because it attempts to convert the object to a char& before 
+    // dereferencing.
+    llvm::raw_string_ostream Out(Result);
+    
+    Out << "#pragma clang diagnostic push\n"
+        << "#pragma clang diagnostic ignored \"-Wc++0x-extensions\"\n"
+        << "namespace std { inline namespace __1 {\n"
+        << "\n";
+    
+    Out << "template <class _Tp>\n"
+        << "inline __attribute__ ((__visibility__(\"hidden\"), "
+        << "__always_inline__))\n"
+        << "__attribute__((objc_lifetime(strong))) _Tp*\n"
+        << "addressof(__attribute__((objc_lifetime(strong))) _Tp& __x) {\n"
+        << "  return &__x;\n"
+        << "}\n"
+        << "\n";
+      
+    if (!LangOpts.ObjCNoAutoRefCountRuntime) {
+      Out << "template <class _Tp>\n"
+          << "inline __attribute__ ((__visibility__(\"hidden\"),"
+          << "__always_inline__))\n"
+          << "__attribute__((objc_lifetime(weak))) _Tp*\n"
+          << "addressof(__attribute__((objc_lifetime(weak))) _Tp& __x) {\n"
+          << "  return &__x;\n"
+          << "};\n"
+          << "\n";
+    }
+      
+    Out << "template <class _Tp>\n"
+        << "inline __attribute__ ((__visibility__(\"hidden\"),"
+        << "__always_inline__))\n"
+        << "__attribute__((objc_lifetime(autoreleasing))) _Tp*\n"
+        << "addressof(__attribute__((objc_lifetime(autoreleasing))) _Tp& __x) "
+        << "{\n"
+        << " return &__x;\n"
+        << "}\n"
+        << "\n";
+    
+    Out << "template <class _Tp>\n"
+        << "inline __attribute__ ((__visibility__(\"hidden\"), "
+        << "__always_inline__))\n"
+        << "__unsafe_unretained _Tp* addressof(__unsafe_unretained _Tp& __x)"
+        << " {\n"
+        << "  return &__x;\n"
+        << "}\n";
+      
+    Out << "\n"
+        << "} }\n"
+        << "#pragma clang diagnostic pop\n"
+        << "\n";    
+  }
+  Builder.append(Result);
+}
+
+/// \brief Add definitions required for a smooth interaction between
+/// Objective-C++ automated reference counting and libstdc++ (4.2).
+static void AddObjCXXARCLibstdcxxDefines(const LangOptions &LangOpts, 
+                                         MacroBuilder &Builder) {
+  Builder.defineMacro("_GLIBCXX_PREDEFINED_OBJC_ARC_IS_SCALAR");
+  
+  std::string Result;
+  {
+    // Provide specializations for the __is_scalar type trait so that 
+    // lifetime-qualified objects are not considered "scalar" types, which
+    // libstdc++ uses as an indicator of the presence of trivial copy, assign,
+    // default-construct, and destruct semantics (none of which hold for
+    // lifetime-qualified objects in ARC).
+    llvm::raw_string_ostream Out(Result);
+    
+    Out << "namespace std {\n"
+        << "\n"
+        << "struct __true_type;\n"
+        << "struct __false_type;\n"
+        << "\n";
+    
+    Out << "template<typename _Tp> struct __is_scalar;\n"
+        << "\n";
+      
+    Out << "template<typename _Tp>\n"
+        << "struct __is_scalar<__attribute__((objc_lifetime(strong))) _Tp> {\n"
+        << "  enum { __value = 0 };\n"
+        << "  typedef __false_type __type;\n"
+        << "};\n"
+        << "\n";
+      
+    if (!LangOpts.ObjCNoAutoRefCountRuntime) {
+      Out << "template<typename _Tp>\n"
+          << "struct __is_scalar<__attribute__((objc_lifetime(weak))) _Tp> {\n"
+          << "  enum { __value = 0 };\n"
+          << "  typedef __false_type __type;\n"
+          << "};\n"
+          << "\n";
+    }
+    
+    Out << "template<typename _Tp>\n"
+        << "struct __is_scalar<__attribute__((objc_lifetime(autoreleasing)))"
+        << " _Tp> {\n"
+        << "  enum { __value = 0 };\n"
+        << "  typedef __false_type __type;\n"
+        << "};\n"
+        << "\n";
+      
+    Out << "}\n";
+  }
+  Builder.append(Result);
+}
+
 static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
                                                const LangOptions &LangOpts,
                                                const FrontendOptions &FEOpts,
@@ -560,6 +679,7 @@
                                    const PreprocessorOptions &InitOpts,
                                    const HeaderSearchOptions &HSOpts,
                                    const FrontendOptions &FEOpts) {
+  const LangOptions &LangOpts = PP.getLangOptions();
   std::string PredefineBuffer;
   PredefineBuffer.reserve(4080);
   llvm::raw_string_ostream Predefines(PredefineBuffer);
@@ -575,10 +695,27 @@
     Builder.append("# 1 \"<built-in>\" 3");
 
   // Install things like __POWERPC__, __GNUC__, etc into the macro table.
-  if (InitOpts.UsePredefines)
-    InitializePredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(),
-                               FEOpts, Builder);
+  if (InitOpts.UsePredefines) {
+    InitializePredefinedMacros(PP.getTargetInfo(), LangOpts, FEOpts, Builder);
 
+    // Install definitions to make Objective-C++ ARC work well with various
+    // C++ Standard Library implementations.
+    if (LangOpts.ObjC1 && LangOpts.CPlusPlus && LangOpts.ObjCAutoRefCount) {
+      switch (InitOpts.ObjCXXARCStandardLibrary) {
+      case ARCXX_nolib:
+        break;
+
+      case ARCXX_libcxx:
+        AddObjCXXARCLibcxxDefines(LangOpts, Builder);
+        break;
+
+      case ARCXX_libstdcxx:
+        AddObjCXXARCLibstdcxxDefines(LangOpts, Builder);
+        break;
+      }
+    }
+  }
+  
   // Even with predefines off, some macros are still predefined.
   // These should all be defined in the preprocessor according to the
   // current language configuration.

Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original)
+++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Wed Jun 15 18:02:42 2011
@@ -551,6 +551,11 @@
            .Case("cxx_exceptions", LangOpts.Exceptions)
            .Case("cxx_rtti", LangOpts.RTTI)
            .Case("enumerator_attributes", true)
+           // Objective-C features
+           .Case("objc_arr", LangOpts.ObjCAutoRefCount) // FIXME: REMOVE?
+           .Case("objc_arc", LangOpts.ObjCAutoRefCount)
+           .Case("objc_arc_weak", LangOpts.ObjCAutoRefCount && 
+                 !LangOpts.ObjCNoAutoRefCountRuntime)
            .Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI)
            .Case("objc_weak_class", LangOpts.ObjCNonFragileABI)
            .Case("ownership_holds", true)

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Wed Jun 15 18:02:42 2011
@@ -31,9 +31,11 @@
 ///
 /// Called type-id in C++.
 TypeResult Parser::ParseTypeName(SourceRange *Range,
-                                 Declarator::TheContext Context) {
+                                 Declarator::TheContext Context,
+                                 ObjCDeclSpec *objcQuals) {
   // Parse the common declaration-specifiers piece.
   DeclSpec DS(AttrFactory);
+  DS.setObjCQualifiers(objcQuals);
   ParseSpecifierQualifierList(DS);
 
   // Parse the abstract-declarator, if present.

Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Wed Jun 15 18:02:42 2011
@@ -1740,7 +1740,12 @@
 ///         '(' type-name ')' '{' initializer-list ',' '}'
 ///       cast-expression: [C99 6.5.4]
 ///         '(' type-name ')' cast-expression
-///
+/// [ARC]   bridged-cast-expression
+/// 
+/// [ARC] bridged-cast-expression:
+///         (__bridge type-name) cast-expression
+///         (__bridge_transfer type-name) cast-expression
+///         (__bridge_retained type-name) cast-expression
 ExprResult
 Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
                              ParsedType TypeOfCast, ParsedType &CastTy,
@@ -1772,7 +1777,30 @@
     // If the substmt parsed correctly, build the AST node.
     if (!Stmt.isInvalid())
       Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.take(), Tok.getLocation());
-
+  } else if (ExprType >= CompoundLiteral && 
+             (Tok.is(tok::kw___bridge) || 
+              Tok.is(tok::kw___bridge_transfer) ||
+              Tok.is(tok::kw___bridge_retained))) {
+    // Parse an Objective-C ARC ownership cast expression.
+    ObjCBridgeCastKind Kind;
+    if (Tok.is(tok::kw___bridge))
+      Kind = OBC_Bridge;
+    else if (Tok.is(tok::kw___bridge_transfer))
+      Kind = OBC_BridgeTransfer;
+    else 
+      Kind = OBC_BridgeRetained;
+             
+    SourceLocation BridgeKeywordLoc = ConsumeToken();
+    TypeResult Ty = ParseTypeName();
+    SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, OpenLoc);
+    ExprResult SubExpr = ParseCastExpression(false, false, ParsedType());
+    
+    if (Ty.isInvalid() || SubExpr.isInvalid())
+      return ExprError();
+    
+    return Actions.ActOnObjCBridgedCast(getCurScope(), OpenLoc, Kind,
+                                        BridgeKeywordLoc, Ty.get(),
+                                        RParenLoc, SubExpr.get());
   } else if (ExprType >= CompoundLiteral &&
              isTypeIdInParens(isAmbiguousTypeId)) {
 

Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
+++ cfe/trunk/lib/Parse/ParseObjc.cpp Wed Jun 15 18:02:42 2011
@@ -480,6 +480,10 @@
 ///     retain
 ///     copy
 ///     nonatomic
+///     atomic
+///     strong
+///     weak
+///     unsafe_unretained
 ///
 void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl) {
   assert(Tok.getKind() == tok::l_paren);
@@ -504,16 +508,22 @@
       DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readonly);
     else if (II->isStr("assign"))
       DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_assign);
+    else if (II->isStr("unsafe_unretained"))
+      DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_unsafe_unretained);
     else if (II->isStr("readwrite"))
       DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_readwrite);
     else if (II->isStr("retain"))
       DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_retain);
+    else if (II->isStr("strong"))
+      DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_strong);
     else if (II->isStr("copy"))
       DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_copy);
     else if (II->isStr("nonatomic"))
       DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nonatomic);
     else if (II->isStr("atomic"))
       DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_atomic);
+    else if (II->isStr("weak"))
+      DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_weak);
     else if (II->isStr("getter") || II->isStr("setter")) {
       bool IsSetter = II->getNameStart()[0] == 's';
 
@@ -775,11 +785,12 @@
 
   ParsedType Ty;
   if (isTypeSpecifierQualifier()) {
-    TypeResult TypeSpec = ParseTypeName(0, Declarator::ObjCPrototypeContext);
+    TypeResult TypeSpec =
+      ParseTypeName(0, Declarator::ObjCPrototypeContext, &DS);
     if (!TypeSpec.isInvalid())
       Ty = TypeSpec.get();
   }
-
+  
   if (Tok.is(tok::r_paren))
     ConsumeParen();
   else if (Tok.getLocation() == TypeStartLoc) {
@@ -853,6 +864,7 @@
   }
 
   // Now parse the selector.
+  SourceLocation SelectorStartLoc = Tok.getLocation();
   SourceLocation selLoc;
   IdentifierInfo *SelIdent = ParseObjCSelectorPiece(selLoc);
 
@@ -1690,6 +1702,29 @@
                                     FinallyStmt.take());
 }
 
+/// objc-autoreleasepool-statement:
+///   @autoreleasepool compound-statement
+///
+StmtResult
+Parser::ParseObjCAutoreleasePoolStmt(SourceLocation atLoc) {
+  ConsumeToken(); // consume autoreleasepool
+  if (Tok.isNot(tok::l_brace)) {
+    Diag(Tok, diag::err_expected_lbrace);
+    return StmtError();
+  }
+  // Enter a scope to hold everything within the compound stmt.  Compound
+  // statements can always hold declarations.
+  ParseScope BodyScope(this, Scope::DeclScope);
+
+  StmtResult AutoreleasePoolBody(ParseCompoundStatementBody());
+
+  BodyScope.Exit();
+  if (AutoreleasePoolBody.isInvalid())
+    AutoreleasePoolBody = Actions.ActOnNullStmt(Tok.getLocation());
+  return Actions.ActOnObjCAutoreleasePoolStmt(atLoc, 
+                                                AutoreleasePoolBody.take());
+}
+
 ///   objc-method-def: objc-method-proto ';'[opt] '{' body '}'
 ///
 Decl *Parser::ParseObjCMethodDefinition() {
@@ -1765,6 +1800,9 @@
   
   if (Tok.isObjCAtKeyword(tok::objc_synchronized))
     return ParseObjCSynchronizedStmt(AtLoc);
+
+  if (Tok.isObjCAtKeyword(tok::objc_autoreleasepool))
+    return ParseObjCAutoreleasePoolStmt(AtLoc);
   
   ExprResult Res(ParseExpressionWithLeadingAt(AtLoc));
   if (Res.isInvalid()) {

Modified: cfe/trunk/lib/Rewrite/FixItRewriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Rewrite/FixItRewriter.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Rewrite/FixItRewriter.cpp (original)
+++ cfe/trunk/lib/Rewrite/FixItRewriter.cpp Wed Jun 15 18:02:42 2011
@@ -121,8 +121,7 @@
 
     if (Hint.CodeToInsert.empty()) {
       // We're removing code.
-      if (Rewrite.RemoveText(Hint.RemoveRange.getBegin(),
-                             Rewrite.getRangeSize(Hint.RemoveRange)))
+      if (Rewrite.RemoveText(Hint.RemoveRange))
         Failed = true;
       continue;
     }

Modified: cfe/trunk/lib/Rewrite/Rewriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Rewrite/Rewriter.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Rewrite/Rewriter.cpp (original)
+++ cfe/trunk/lib/Rewrite/Rewriter.cpp Wed Jun 15 18:02:42 2011
@@ -231,10 +231,44 @@
 /// InsertText - Insert the specified string at the specified location in the
 /// original buffer.
 bool Rewriter::InsertText(SourceLocation Loc, llvm::StringRef Str,
-                          bool InsertAfter) {
+                          bool InsertAfter, bool indentNewLines) {
+  using llvm::StringRef;
+
   if (!isRewritable(Loc)) return true;
   FileID FID;
   unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID);
+
+  llvm::SmallString<128> indentedStr;
+  if (indentNewLines && Str.find('\n') != StringRef::npos) {
+    StringRef MB = SourceMgr->getBufferData(FID);
+
+    unsigned lineNo = SourceMgr->getLineNumber(FID, StartOffs) - 1;
+    const SrcMgr::ContentCache *
+        Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache();
+    unsigned lineOffs = Content->SourceLineCache[lineNo];
+
+    // Find the whitespace at the start of the line.
+    StringRef indentSpace;
+    {
+      unsigned i = lineOffs;
+      while (isWhitespace(MB[i]))
+        ++i;
+      indentSpace = MB.substr(lineOffs, i-lineOffs);
+    }
+
+    llvm::SmallVector<StringRef, 4> lines;
+    Str.split(lines, "\n");
+
+    for (unsigned i = 0, e = lines.size(); i != e; ++i) {
+      indentedStr += lines[i];
+      if (i < e-1) {
+        indentedStr += '\n';
+        indentedStr += indentSpace;
+      }
+    }
+    Str = indentedStr.str();
+  }
+
   getEditBuffer(FID).InsertText(StartOffs, Str, InsertAfter);
   return false;
 }
@@ -317,6 +351,7 @@
                                    SourceLocation parentIndent) {
   using llvm::StringRef;
 
+  if (range.isInvalid()) return true;
   if (!isRewritable(range.getBegin())) return true;
   if (!isRewritable(range.getEnd())) return true;
   if (!isRewritable(parentIndent)) return true;
@@ -330,7 +365,7 @@
 
   if (StartFileID != EndFileID || StartFileID != parentFileID)
     return true;
-  if (StartOff >= EndOff || parentOff >= StartOff)
+  if (StartOff > EndOff)
     return true;
 
   FileID FID = StartFileID;
@@ -343,16 +378,12 @@
   const SrcMgr::ContentCache *
       Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache();
   
-  // Find where the line starts for the three offsets.
+  // Find where the lines start.
   unsigned parentLineOffs = Content->SourceLineCache[parentLineNo];
   unsigned startLineOffs = Content->SourceLineCache[startLineNo];
-  unsigned endLineOffs = Content->SourceLineCache[endLineNo];
-
-  if (startLineOffs == endLineOffs || startLineOffs == parentLineOffs)
-    return true;
 
   // Find the whitespace at the start of each line.
-  StringRef parentSpace, startSpace, endSpace;
+  StringRef parentSpace, startSpace;
   {
     unsigned i = parentLineOffs;
     while (isWhitespace(MB[i]))
@@ -363,11 +394,6 @@
     while (isWhitespace(MB[i]))
       ++i;
     startSpace = MB.substr(startLineOffs, i-startLineOffs);
-
-    i = endLineOffs;
-    while (isWhitespace(MB[i]))
-      ++i;
-    endSpace = MB.substr(endLineOffs, i-endLineOffs);
   }
   if (parentSpace.size() >= startSpace.size())
     return true;
@@ -378,19 +404,14 @@
 
   // Indent the lines between start/end offsets.
   RewriteBuffer &RB = getEditBuffer(FID);
-  for (unsigned i = startLineOffs; i != endLineOffs; ++i) {
-    if (MB[i] == '\n') {
-      unsigned startOfLine = i+1;
-      if (startOfLine == endLineOffs)
-        break;
-      StringRef origIndent;
-      unsigned ws = startOfLine;
-      while (isWhitespace(MB[ws]))
-        ++ws;
-      origIndent = MB.substr(startOfLine, ws-startOfLine);
-      if (origIndent.startswith(startSpace))
-        RB.InsertText(startOfLine, indent, /*InsertAfter=*/false);
-    }
+  for (unsigned lineNo = startLineNo; lineNo <= endLineNo; ++lineNo) {
+    unsigned offs = Content->SourceLineCache[lineNo];
+    unsigned i = offs;
+    while (isWhitespace(MB[i]))
+      ++i;
+    StringRef origIndent = MB.substr(offs, i-offs);
+    if (origIndent.startswith(startSpace))
+      RB.InsertText(offs, indent, /*InsertAfter=*/false);
   }
 
   return false;

Modified: cfe/trunk/lib/Sema/AttributeList.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AttributeList.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/AttributeList.cpp (original)
+++ cfe/trunk/lib/Sema/AttributeList.cpp Wed Jun 15 18:02:42 2011
@@ -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)

Modified: cfe/trunk/lib/Sema/DelayedDiagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/DelayedDiagnostic.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/DelayedDiagnostic.cpp (original)
+++ cfe/trunk/lib/Sema/DelayedDiagnostic.cpp Wed Jun 15 18:02:42 2011
@@ -47,5 +47,8 @@
   case Deprecation: 
     delete [] DeprecationData.Message;
     break;
+
+  case ForbiddenType:
+    break;
   }
 }

Modified: cfe/trunk/lib/Sema/JumpDiagnostics.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/JumpDiagnostics.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/JumpDiagnostics.cpp (original)
+++ cfe/trunk/lib/Sema/JumpDiagnostics.cpp Wed Jun 15 18:02:42 2011
@@ -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);
   }

Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Wed Jun 15 18:02:42 2011
@@ -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() {

Modified: cfe/trunk/lib/Sema/SemaCXXCast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXCast.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXCast.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXCast.cpp Wed Jun 15 18:02:42 2011
@@ -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;

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Wed Jun 15 18:02:42 2011
@@ -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();
+}
+

Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Wed Jun 15 18:02:42 2011
@@ -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) {

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Jun 15 18:02:42 2011
@@ -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())

Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Wed Jun 15 18:02:42 2011
@@ -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;
       }
     }
   }

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Jun 15 18:02:42 2011
@@ -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())

Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Wed Jun 15 18:02:42 2011
@@ -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());
-
-  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))
+bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left,
+                                      const ObjCMethodDecl *right,
+                                      MethodMatchStrategy strategy) {
+  if (!matchTypes(Context, strategy,
+                  left->getResultType(), right->getResultType()))
+    return false;
+
+  if (getLangOptions().ObjCAutoRefCount &&
+      (left->hasAttr<NSReturnsRetainedAttr>()
+         != right->hasAttr<NSReturnsRetainedAttr>() ||
+       left->hasAttr<NSConsumesSelfAttr>()
+         != right->hasAttr<NSConsumesSelfAttr>()))
+    return false;
+
+  ObjCMethodDecl::param_iterator
+    li = left->param_begin(), le = left->param_end(), ri = right->param_begin();
+
+  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;
-  }
 
-  ObjCMethodDecl::param_iterator ParamI = Method->param_begin(),
-       E = Method->param_end();
-  ObjCMethodDecl::param_iterator PrevI = PrevMethod->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;
-    }
+    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()) {

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Jun 15 18:02:42 2011
@@ -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;

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Jun 15 18:02:42 2011
@@ -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,17 +3908,84 @@
   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);
+  }
 
-  const RecordType *RT = E->getType()->getAs<RecordType>();
-  if (!RT)
+  if (!getLangOptions().CPlusPlus)
     return Owned(E);
 
-  // If the result is a glvalue, we shouldn't bind it.
-  if (E->Classify(Context).isGLValue())
+  const RecordType *RT = E->getType()->getAs<RecordType>();
+  if (!RT)
     return Owned(E);
 
   // That should be enough to guarantee that this type is complete.
@@ -3847,15 +3994,18 @@
   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();
-
-      // Recover by setting the destructed type to the object type.
-      DestructedType = ObjectType;
-      DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType,
+    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,
                                                            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);
+      }
     }
   }
 

Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Wed Jun 15 18:02:42 2011
@@ -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);
+}

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Wed Jun 15 18:02:42 2011
@@ -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;
     }
   }
 }

Modified: cfe/trunk/lib/Sema/SemaObjCProperty.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaObjCProperty.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaObjCProperty.cpp (original)
+++ cfe/trunk/lib/Sema/SemaObjCProperty.cpp Wed Jun 15 18:02:42 2011
@@ -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 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 (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);
+    }
 
     // FIXME: Implement warning dependent on NSCopying being
     // implemented. See also:

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Jun 15 18:02:42 2011
@@ -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();
   }

Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Wed Jun 15 18:02:42 2011
@@ -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 {

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Jun 15 18:02:42 2011
@@ -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() &&

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Wed Jun 15 18:02:42 2011
@@ -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);
     

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Wed Jun 15 18:02:42 2011
@@ -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.

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Wed Jun 15 18:02:42 2011
@@ -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.

Modified: cfe/trunk/lib/Sema/TypeLocBuilder.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TypeLocBuilder.h?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TypeLocBuilder.h (original)
+++ cfe/trunk/lib/Sema/TypeLocBuilder.h Wed Jun 15 18:02:42 2011
@@ -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) {

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Wed Jun 15 18:02:42 2011
@@ -147,9 +147,11 @@
   PARSE_LANGOPT_IMPORTANT(OpenCL, diag::warn_pch_opencl);
   PARSE_LANGOPT_IMPORTANT(CUDA, diag::warn_pch_cuda);
   PARSE_LANGOPT_BENIGN(CatchUndefined);
+  PARSE_LANGOPT_BENIGN(DefaultFPContract);
   PARSE_LANGOPT_IMPORTANT(ElideConstructors, diag::warn_pch_elide_constructors);
   PARSE_LANGOPT_BENIGN(SpellChecking);
-  PARSE_LANGOPT_BENIGN(DefaultFPContract);
+  PARSE_LANGOPT_IMPORTANT(ObjCAutoRefCount, diag::warn_pch_auto_ref_count);
+  PARSE_LANGOPT_BENIGN(ObjCInferRelatedReturnType);
 #undef PARSE_LANGOPT_IMPORTANT
 #undef PARSE_LANGOPT_BENIGN
 
@@ -2980,6 +2982,7 @@
     PARSE_LANGOPT(ElideConstructors);
     PARSE_LANGOPT(SpellChecking);
     PARSE_LANGOPT(MRTD);
+    PARSE_LANGOPT(ObjCAutoRefCount);
   #undef PARSE_LANGOPT
 
     return Listener->ReadLanguageOptions(LangOpts);
@@ -3225,12 +3228,13 @@
   }
 
   case TYPE_FUNCTION_NO_PROTO: {
-    if (Record.size() != 5) {
+    if (Record.size() != 6) {
       Error("incorrect encoding of no-proto function type");
       return QualType();
     }
     QualType ResultType = GetType(Record[0]);
-    FunctionType::ExtInfo Info(Record[1], Record[2], Record[3], (CallingConv)Record[4]);
+    FunctionType::ExtInfo Info(Record[1], Record[2], Record[3],
+                               (CallingConv)Record[4], Record[5]);
     return Context->getFunctionNoProtoType(ResultType, Info);
   }
 
@@ -3241,9 +3245,10 @@
     EPI.ExtInfo = FunctionType::ExtInfo(/*noreturn*/ Record[1],
                                         /*hasregparm*/ Record[2],
                                         /*regparm*/ Record[3],
-                                        static_cast<CallingConv>(Record[4]));
+                                        static_cast<CallingConv>(Record[4]),
+                                        /*produces*/ Record[5]);
 
-    unsigned Idx = 5;
+    unsigned Idx = 6;
     unsigned NumParams = Record[Idx++];
     llvm::SmallVector<QualType, 16> ParamTypes;
     for (unsigned I = 0; I != NumParams; ++I)

Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Wed Jun 15 18:02:42 2011
@@ -131,6 +131,8 @@
     void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E);
     void VisitObjCMessageExpr(ObjCMessageExpr *E);
     void VisitObjCIsaExpr(ObjCIsaExpr *E);
+    void VisitObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E);
+    void VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *E);
 
     void VisitObjCForCollectionStmt(ObjCForCollectionStmt *);
     void VisitObjCAtCatchStmt(ObjCAtCatchStmt *);
@@ -138,6 +140,7 @@
     void VisitObjCAtTryStmt(ObjCAtTryStmt *);
     void VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *);
     void VisitObjCAtThrowStmt(ObjCAtThrowStmt *);
+    void VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *);
 
     // C++ Statements
     void VisitCXXCatchStmt(CXXCatchStmt *S);
@@ -602,6 +605,20 @@
   E->setArrow(Record[Idx++]);
 }
 
+void ASTStmtReader::
+VisitObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) {
+  VisitExpr(E);
+  E->Operand = Reader.ReadSubExpr();
+  E->setShouldCopy(Record[Idx++]);
+}
+
+void ASTStmtReader::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
+  VisitExplicitCastExpr(E);
+  E->LParenLoc = ReadSourceLocation(Record, Idx);
+  E->BridgeKeywordLoc = ReadSourceLocation(Record, Idx);
+  E->Kind = Record[Idx++];
+}
+
 void ASTStmtReader::VisitCastExpr(CastExpr *E) {
   VisitExpr(E);
   unsigned NumBaseSpecs = Record[Idx++];
@@ -929,6 +946,7 @@
   VisitExpr(E);
   assert(Record[Idx] == E->getNumArgs());
   ++Idx;
+  E->setDelegateInitCall(Record[Idx++]);
   ObjCMessageExpr::ReceiverKind Kind
     = static_cast<ObjCMessageExpr::ReceiverKind>(Record[Idx++]);
   switch (Kind) {
@@ -987,6 +1005,12 @@
   S->setAtFinallyLoc(ReadSourceLocation(Record, Idx));
 }
 
+void ASTStmtReader::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
+  VisitStmt(S);
+  S->setSubStmt(Reader.ReadSubStmt());
+  S->setAtLoc(ReadSourceLocation(Record, Idx));
+}
+
 void ASTStmtReader::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
   VisitStmt(S);
   assert(Record[Idx] == S->getNumCatchStmts());
@@ -1784,6 +1808,12 @@
     case EXPR_OBJC_ISA:
       S = new (Context) ObjCIsaExpr(Empty);
       break;
+    case EXPR_OBJC_INDIRECT_COPY_RESTORE:
+      S = new (Context) ObjCIndirectCopyRestoreExpr(Empty);
+      break;
+    case EXPR_OBJC_BRIDGED_CAST:
+      S = new (Context) ObjCBridgedCastExpr(Empty);
+      break;
     case STMT_OBJC_FOR_COLLECTION:
       S = new (Context) ObjCForCollectionStmt(Empty);
       break;
@@ -1804,7 +1834,9 @@
     case STMT_OBJC_AT_THROW:
       S = new (Context) ObjCAtThrowStmt(Empty);
       break;
-
+    case STMT_OBJC_AUTORELEASE_POOL:
+      S = new (Context) ObjCAutoreleasePoolStmt(Empty);
+      break;
     case STMT_CXX_CATCH:
       S = new (Context) CXXCatchStmt(Empty);
       break;

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Wed Jun 15 18:02:42 2011
@@ -170,6 +170,7 @@
   Record.push_back(C.getRegParm());
   // FIXME: need to stabilize encoding of calling convention...
   Record.push_back(C.getCC());
+  Record.push_back(C.getProducesResult());
 }
 
 void ASTTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
@@ -1109,6 +1110,8 @@
   Record.push_back(LangOpts.ElideConstructors);
   Record.push_back(LangOpts.SpellChecking);
   Record.push_back(LangOpts.MRTD);
+  Record.push_back(LangOpts.ObjCAutoRefCount);
+  Record.push_back(LangOpts.ObjCInferRelatedReturnType);
   Stream.EmitRecord(LANGUAGE_OPTIONS, Record);
 }
 

Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Wed Jun 15 18:02:42 2011
@@ -105,6 +105,8 @@
     void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E);
     void VisitObjCMessageExpr(ObjCMessageExpr *E);
     void VisitObjCIsaExpr(ObjCIsaExpr *E);
+    void VisitObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E);
+    void VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *E);
 
     // Objective-C Statements
     void VisitObjCForCollectionStmt(ObjCForCollectionStmt *);
@@ -113,6 +115,7 @@
     void VisitObjCAtTryStmt(ObjCAtTryStmt *);
     void VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *);
     void VisitObjCAtThrowStmt(ObjCAtThrowStmt *);
+    void VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *);
 
     // C++ Statements
     void VisitCXXCatchStmt(CXXCatchStmt *S);
@@ -606,6 +609,22 @@
   Code = serialization::EXPR_OBJC_ISA;
 }
 
+void ASTStmtWriter::
+VisitObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) {
+  VisitExpr(E);
+  Writer.AddStmt(E->getSubExpr());
+  Record.push_back(E->shouldCopy());
+  Code = serialization::EXPR_OBJC_INDIRECT_COPY_RESTORE;
+}
+
+void ASTStmtWriter::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
+  VisitExplicitCastExpr(E);
+  Writer.AddSourceLocation(E->getLParenLoc(), Record);
+  Writer.AddSourceLocation(E->getBridgeKeywordLoc(), Record);
+  Record.push_back(E->getBridgeKind()); // FIXME: Stable encoding
+  Code = serialization::EXPR_OBJC_BRIDGED_CAST;
+}
+
 void ASTStmtWriter::VisitCastExpr(CastExpr *E) {
   VisitExpr(E);
   Record.push_back(E->path_size());
@@ -914,6 +933,7 @@
 void ASTStmtWriter::VisitObjCMessageExpr(ObjCMessageExpr *E) {
   VisitExpr(E);
   Record.push_back(E->getNumArgs());
+  Record.push_back(E->isDelegateInitCall());
   Record.push_back((unsigned)E->getReceiverKind()); // FIXME: stable encoding
   switch (E->getReceiverKind()) {
   case ObjCMessageExpr::Instance:
@@ -973,6 +993,12 @@
   Code = serialization::STMT_OBJC_FINALLY;
 }
 
+void ASTStmtWriter::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
+  Writer.AddStmt(S->getSubStmt());
+  Writer.AddSourceLocation(S->getAtLoc(), Record);
+  Code = serialization::STMT_OBJC_AUTORELEASE_POOL;
+}
+
 void ASTStmtWriter::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
   Record.push_back(S->getNumCatchStmts());
   Record.push_back(S->getFinallyStmt() != 0);

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp Wed Jun 15 18:02:42 2011
@@ -254,13 +254,13 @@
             return;
             
           if (Expr* E = V->getInit()) {
+            while (ExprWithCleanups *exprClean = dyn_cast<ExprWithCleanups>(E))
+              E = exprClean->getSubExpr();
+            
             // Don't warn on C++ objects (yet) until we can show that their
             // constructors/destructors don't have side effects.
             if (isa<CXXConstructExpr>(E))
               return;
-
-            if (isa<ExprWithCleanups>(E))
-              return;
             
             // A dead initialization is a variable that is dead after it
             // is initialized.  We don't flag warnings for those variables

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp Wed Jun 15 18:02:42 2011
@@ -121,6 +121,11 @@
     return;  
   
   if (R->hasStackStorage()) {
+    // Automatic reference counting automatically copies blocks.
+    if (C.getASTContext().getLangOptions().ObjCAutoRefCount &&
+        isa<BlockDataRegion>(R))
+      return;
+
     EmitStackError(C, R, RetE);
     return;
   }
@@ -135,12 +140,13 @@
   // a memory region in the stack space.
   class CallBack : public StoreManager::BindingsHandler {
   private:
+    ExprEngine &Eng;
     const StackFrameContext *CurSFC;
   public:
     llvm::SmallVector<std::pair<const MemRegion*, const MemRegion*>, 10> V;
 
-    CallBack(const LocationContext *LCtx)
-      : CurSFC(LCtx->getCurrentStackFrame()) {}
+    CallBack(ExprEngine &Eng, const LocationContext *LCtx)
+      : Eng(Eng), CurSFC(LCtx->getCurrentStackFrame()) {}
     
     bool HandleBinding(StoreManager &SMgr, Store store,
                        const MemRegion *region, SVal val) {
@@ -151,7 +157,13 @@
       const MemRegion *vR = val.getAsRegion();
       if (!vR)
         return true;
-      
+        
+      // Under automated retain release, it is okay to assign a block
+      // directly to a global variable.
+      if (Eng.getContext().getLangOptions().ObjCAutoRefCount &&
+          isa<BlockDataRegion>(vR))
+        return true;
+
       if (const StackSpaceRegion *SSR = 
           dyn_cast<StackSpaceRegion>(vR->getMemorySpace())) {
         // If the global variable holds a location in the current stack frame,
@@ -164,7 +176,7 @@
     }
   };
     
-  CallBack cb(B.getPredecessor()->getLocationContext());
+  CallBack cb(Eng, B.getPredecessor()->getLocationContext());
   state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb);
 
   if (cb.V.empty())

Modified: cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp Wed Jun 15 18:02:42 2011
@@ -126,6 +126,7 @@
 /// ArgEffect is used to summarize a function/method call's effect on a
 /// particular argument.
 enum ArgEffect { Autorelease, Dealloc, DecRef, DecRefMsg, DoNothing,
+                 DecRefBridgedTransfered,
                  DoNothingByRef, IncRefMsg, IncRef, MakeCollectable, MayEscape,
                  NewAutoreleasePool, SelfOwn, StopTracking };
 
@@ -148,7 +149,8 @@
 class RetEffect {
 public:
   enum Kind { NoRet, Alias, OwnedSymbol, OwnedAllocatedSymbol,
-              NotOwnedSymbol, GCNotOwnedSymbol, ReceiverAlias,
+              NotOwnedSymbol, GCNotOwnedSymbol, ARCNotOwnedSymbol,
+              ReceiverAlias,
               OwnedWhenTrackedReceiver };
 
   enum ObjKind { CF, ObjC, AnyObj };
@@ -195,7 +197,9 @@
   static RetEffect MakeGCNotOwned() {
     return RetEffect(GCNotOwnedSymbol, ObjC);
   }
-
+  static RetEffect MakeARCNotOwned() {
+    return RetEffect(ARCNotOwnedSymbol, ObjC);
+  }
   static RetEffect MakeNoRet() {
     return RetEffect(NoRet);
   }
@@ -636,6 +640,9 @@
   /// GCEnabled - Records whether or not the analyzed code runs in GC mode.
   const bool GCEnabled;
 
+  /// Records whether or not the analyzed code runs in ARC mode.
+  const bool ARCEnabled;
+
   /// FuncSummaries - A map from FunctionDecls to summaries.
   FuncSummariesTy FuncSummaries;
 
@@ -788,14 +795,20 @@
 
 public:
 
-  RetainSummaryManager(ASTContext& ctx, bool gcenabled)
+  RetainSummaryManager(ASTContext& ctx, bool gcenabled, bool usesARC)
    : Ctx(ctx),
      CFDictionaryCreateII(&ctx.Idents.get("CFDictionaryCreate")),
-     GCEnabled(gcenabled), AF(BPAlloc), ScratchArgs(AF.getEmptyMap()),
-     ObjCAllocRetE(gcenabled ? RetEffect::MakeGCNotOwned()
-                             : RetEffect::MakeOwned(RetEffect::ObjC, true)),
-     ObjCInitRetE(gcenabled ? RetEffect::MakeGCNotOwned()
-                            : RetEffect::MakeOwnedWhenTrackedReceiver()),
+     GCEnabled(gcenabled),
+     ARCEnabled(usesARC),
+     AF(BPAlloc), ScratchArgs(AF.getEmptyMap()),
+     ObjCAllocRetE(gcenabled
+                    ? RetEffect::MakeGCNotOwned()
+                    : (usesARC ? RetEffect::MakeARCNotOwned()
+                               : RetEffect::MakeOwned(RetEffect::ObjC, true))),
+     ObjCInitRetE(gcenabled 
+                    ? RetEffect::MakeGCNotOwned()
+                    : (usesARC ? RetEffect::MakeARCNotOwned()
+                               : RetEffect::MakeOwnedWhenTrackedReceiver())),
      DefaultSummary(AF.getEmptyMap() /* per-argument effects (none) */,
                     RetEffect::MakeNoRet() /* return effect */,
                     MayEscape, /* default argument effect */
@@ -871,6 +884,10 @@
 
   bool isGCEnabled() const { return GCEnabled; }
 
+  bool isARCEnabled() const { return ARCEnabled; }
+  
+  bool isARCorGCEnabled() const { return GCEnabled || ARCEnabled; }
+
   RetainSummary *copySummary(RetainSummary *OldSumm) {
     RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>();
     new (Summ) RetainSummary(*OldSumm);
@@ -1654,7 +1671,6 @@
                        const char* nl, const char* sep);
   };
 
-private:
   typedef llvm::DenseMap<const ExplodedNode*, const RetainSummary*>
     SummaryLogTy;
 
@@ -1691,7 +1707,7 @@
 
 public:
   CFRefCount(ASTContext& Ctx, bool gcenabled, const LangOptions& lopts)
-    : Summaries(Ctx, gcenabled),
+    : Summaries(Ctx, gcenabled, (bool)lopts.ObjCAutoRefCount),
       LOpts(lopts), useAfterRelease(0), releaseNotOwned(0),
       deallocGC(0), deallocNotOwned(0),
       leakWithinFunction(0), leakAtReturn(0), overAutorelease(0),
@@ -1706,6 +1722,8 @@
   }
 
   bool isGCEnabled() const { return Summaries.isGCEnabled(); }
+  bool isARCorGCEnabled() const { return Summaries.isARCorGCEnabled(); }
+  
   const LangOptions& getLangOptions() const { return LOpts; }
 
   const RetainSummary *getSummaryOfNode(const ExplodedNode *N) const {
@@ -2777,6 +2795,7 @@
     }
 
     case RetEffect::GCNotOwnedSymbol:
+    case RetEffect::ARCNotOwnedSymbol:
     case RetEffect::NotOwnedSymbol: {
       unsigned Count = Builder.getCurrentBlockCount();
       SValBuilder &svalBuilder = Eng.getSValBuilder();
@@ -3103,8 +3122,8 @@
   // In GC mode [... release] and [... retain] do nothing.
   switch (E) {
     default: break;
-    case IncRefMsg: E = isGCEnabled() ? DoNothing : IncRef; break;
-    case DecRefMsg: E = isGCEnabled() ? DoNothing : DecRef; break;
+    case IncRefMsg: E = isARCorGCEnabled() ? DoNothing : IncRef; break;
+    case DecRefMsg: E = isARCorGCEnabled() ? DoNothing : DecRef; break;
     case MakeCollectable: E = isGCEnabled() ? DecRef : DoNothing; break;
     case NewAutoreleasePool: E = isGCEnabled() ? DoNothing :
                                                  NewAutoreleasePool; break;
@@ -3118,9 +3137,13 @@
   }
 
   switch (E) {
-    default:
-      assert (false && "Unhandled CFRef transition.");
-
+    case DecRefMsg:
+    case IncRefMsg:
+    case MakeCollectable:
+      assert(false &&
+             "DecRefMsg/IncRefMsg/MakeCollectable already transformed");
+      return state;
+      
     case Dealloc:
       // Any use of -dealloc in GC is *bad*.
       if (isGCEnabled()) {
@@ -3193,6 +3216,7 @@
       V = V ^ RefVal::NotOwned;
       // Fall-through.
     case DecRef:
+    case DecRefBridgedTransfered:
       switch (V.getKind()) {
         default:
           // case 'RefVal::Released' handled above.
@@ -3200,7 +3224,9 @@
 
         case RefVal::Owned:
           assert(V.getCount() > 0);
-          if (V.getCount() == 1) V = V ^ RefVal::Released;
+          if (V.getCount() == 1)
+            V = V ^ (E == DecRefBridgedTransfered ? 
+                      RefVal::NotOwned : RefVal::Released);
           V = V - 1;
           break;
 
@@ -3468,7 +3494,9 @@
 
 namespace {
 class RetainReleaseChecker
-  : public Checker< check::PostStmt<BlockExpr>, check::RegionChanges > {
+  : public Checker< check::PostStmt<BlockExpr>,
+                    check::PostStmt<CastExpr>,
+                    check::RegionChanges > {
 public:
     bool wantsRegionUpdate;
     
@@ -3476,6 +3504,9 @@
     
     
     void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
+                      
+    void checkPostStmt(const CastExpr *CE, CheckerContext &C) const;
+
     const GRState *checkRegionChanges(const GRState *state,
                             const StoreManager::InvalidatedSymbols *invalidated,
                                       const MemRegion * const *begin,
@@ -3545,6 +3576,48 @@
   C.addTransition(state);
 }
 
+void RetainReleaseChecker::checkPostStmt(const CastExpr *CE,
+                                         CheckerContext &C) const {
+  const ObjCBridgedCastExpr *BE = dyn_cast<ObjCBridgedCastExpr>(CE);
+  if (!BE)
+    return;
+  
+  ArgEffect AE;
+  
+  switch (BE->getBridgeKind()) {
+    case clang::OBC_Bridge:
+      // Do nothing.
+      return;
+    case clang::OBC_BridgeRetained:
+      AE = IncRef;
+      break;      
+    case clang::OBC_BridgeTransfer:
+      AE = DecRefBridgedTransfered;
+      break;
+  }
+  
+  const GRState *state = C.getState();
+  SymbolRef Sym = state->getSVal(CE).getAsLocSymbol();
+  if (!Sym)
+    return;
+  const RefVal* T = state->get<RefBindings>(Sym);
+  if (!T)
+    return;
+
+  // This is gross.  Once the checker and CFRefCount are unified,
+  // this will go away.
+  CFRefCount &cf = static_cast<CFRefCount&>(C.getEngine().getTF());
+  RefVal::Kind hasErr = (RefVal::Kind) 0;
+  state = cf.Update(state, Sym, *T, AE, hasErr);
+  
+  if (hasErr) {
+    
+    return;
+  }
+
+  C.generateNode(state);
+}
+
 //===----------------------------------------------------------------------===//
 // Transfer function creation for external clients.
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Wed Jun 15 18:02:42 2011
@@ -442,7 +442,8 @@
   }
 
   switch (S->getStmtClass()) {
-    // C++ stuff we don't support yet.
+    // C++ and ARC stuff we don't support yet.
+    case Expr::ObjCIndirectCopyRestoreExprClass:
     case Stmt::CXXBindTemporaryExprClass:
     case Stmt::CXXCatchStmtClass:
     case Stmt::CXXDependentScopeMemberExprClass:
@@ -520,14 +521,27 @@
       VisitObjCPropertyRefExpr(cast<ObjCPropertyRefExpr>(S), Pred, Dst);
       break;
 
+    case Stmt::ImplicitValueInitExprClass: {
+      const GRState *state = GetState(Pred);
+      QualType ty = cast<ImplicitValueInitExpr>(S)->getType();
+      SVal val = svalBuilder.makeZeroVal(ty);
+      MakeNode(Dst, S, Pred, state->BindExpr(S, val));
+      break;
+    }
+      
+    case Stmt::ExprWithCleanupsClass: {
+      Visit(cast<ExprWithCleanups>(S)->getSubExpr(), Pred, Dst);
+      break;
+    }
+
     // Cases not handled yet; but will handle some day.
     case Stmt::DesignatedInitExprClass:
     case Stmt::ExtVectorElementExprClass:
     case Stmt::ImaginaryLiteralClass:
-    case Stmt::ImplicitValueInitExprClass:
     case Stmt::ObjCAtCatchStmtClass:
     case Stmt::ObjCAtFinallyStmtClass:
     case Stmt::ObjCAtTryStmtClass:
+    case Stmt::ObjCAutoreleasePoolStmtClass:
     case Stmt::ObjCEncodeExprClass:
     case Stmt::ObjCIsaExprClass:
     case Stmt::ObjCProtocolExprClass:
@@ -548,7 +562,6 @@
     case Stmt::IntegerLiteralClass:
     case Stmt::CharacterLiteralClass:
     case Stmt::CXXBoolLiteralExprClass:
-    case Stmt::ExprWithCleanupsClass:
     case Stmt::FloatingLiteralClass:
     case Stmt::SizeOfPackExprClass:
     case Stmt::CXXNullPtrLiteralExprClass:
@@ -668,9 +681,22 @@
     case Stmt::CXXDynamicCastExprClass:
     case Stmt::CXXReinterpretCastExprClass:
     case Stmt::CXXConstCastExprClass:
-    case Stmt::CXXFunctionalCastExprClass: {
+    case Stmt::CXXFunctionalCastExprClass: 
+    case Stmt::ObjCBridgedCastExprClass: {
       const CastExpr* C = cast<CastExpr>(S);
-      VisitCast(C, C->getSubExpr(), Pred, Dst);
+      // Handle the previsit checks.
+      ExplodedNodeSet dstPrevisit;
+      getCheckerManager().runCheckersForPreStmt(dstPrevisit, Pred, C, *this);
+      
+      // Handle the expression itself.
+      ExplodedNodeSet dstExpr;
+      for (ExplodedNodeSet::iterator i = dstPrevisit.begin(),
+                                     e = dstPrevisit.end(); i != e ; ++i) { 
+        VisitCast(C, C->getSubExpr(), *i, dstExpr);
+      }
+
+      // Handle the postvisit checks.
+      getCheckerManager().runCheckersForPostStmt(Dst, dstExpr, C, *this);
       break;
     }
 
@@ -2148,10 +2174,18 @@
     Pred = *I;
 
     switch (CastE->getCastKind()) {
+      case CK_LValueToRValue:
+        assert(false && "LValueToRValue casts handled earlier.");
+      case CK_GetObjCProperty:
+        assert(false && "GetObjCProperty casts handled earlier.");
       case CK_ToVoid:
         Dst.Add(Pred);
         continue;
-      case CK_LValueToRValue:
+      // The analyzer doesn't do anything special with these casts,
+      // since it understands retain/release semantics already.
+      case CK_ObjCProduceObject:
+      case CK_ObjCConsumeObject: // Fall-through.
+      // True no-ops.
       case CK_NoOp:
       case CK_FunctionToPointerDecay: {
         // Copy the SVal of Ex to CastE.
@@ -2161,7 +2195,6 @@
         MakeNode(Dst, CastE, Pred, state);
         continue;
       }
-      case CK_GetObjCProperty:
       case CK_Dependent:
       case CK_ArrayToPointerDecay:
       case CK_BitCast:

Added: cfe/trunk/test/Analysis/objc-arc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/objc-arc.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/objc-arc.m (added)
+++ cfe/trunk/test/Analysis/objc-arc.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,149 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core -analyzer-checker=deadcode -analyzer-store=region -verify -fblocks  -analyzer-opt-analyze-nested-blocks -fobjc-nonfragile-abi -fobjc-arc %s
+
+typedef signed char BOOL;
+typedef struct _NSZone NSZone;
+ at class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+
+ at protocol NSObject
+- (BOOL)isEqual:(id)object;
+ at end
+ at protocol NSCopying
+- (id)copyWithZone:(NSZone *)zone;
+ at end
+ at protocol NSCoding
+- (void)encodeWithCoder:(NSCoder *)aCoder;
+ at end
+ at interface NSObject <NSObject> {}
++ (id)alloc;
+ at end
+typedef const struct __CFAllocator * CFAllocatorRef;
+extern const CFAllocatorRef kCFAllocatorDefault;
+typedef double CFTimeInterval;
+typedef CFTimeInterval CFAbsoluteTime;
+extern CFAbsoluteTime CFAbsoluteTimeGetCurrent(void);
+typedef const struct __CFDate * CFDateRef;
+extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at);
+
+typedef const void* objc_objectptr_t;
+__attribute__((ns_returns_retained)) id objc_retainedObject(objc_objectptr_t __attribute__((cf_consumed)) pointer);
+__attribute__((ns_returns_not_retained)) id objc_unretainedObject(objc_objectptr_t pointer);
+
+// Test the analyzer is working at all.
+void test_working() {
+  int *p = 0;
+  *p = 0xDEADBEEF; // expected-warning {{null}}
+}
+
+// Test that in ARC mode that blocks are correctly automatically copied
+// and not flagged as warnings by the analyzer.
+typedef void (^Block)(void);
+void testblock_bar(int x);
+
+Block testblock_foo(int x) {
+  Block b = ^{ testblock_bar(x); };
+  return b; // no-warning
+}
+
+Block testblock_baz(int x) {
+  return ^{ testblock_bar(x); }; // no-warning
+}
+
+Block global_block;
+
+void testblock_qux(int x) {
+  global_block = ^{ testblock_bar(x); }; // no-warning
+}
+
+// Test that Objective-C pointers are null initialized.
+void test_nil_initialized() {
+  id x;
+  if (x == 0)
+    return;
+  int *p = 0;
+  *p = 0xDEADBEEF; // no-warning
+}
+
+// Test that we don't flag leaks of Objective-C objects.
+void test_alloc() {
+  [NSObject alloc]; // no-warning
+}
+
+// Test that CF allocations are still caught as leaks.
+void test_cf_leak() {
+  CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+  CFDateRef date = CFDateCreate(0, t); // expected-warning {{Potential leak}}
+  (void) date;
+}
+
+// Test that 'init' methods do not try to claim ownerhip of an *unowned* allocated object
+// in ARC mode.
+ at interface RDar9424890_A :  NSObject
+- (id)initWithCleaner:(int)pop mop:(NSString *)mop ;
+- (RDar9424890_A *)rdar9424890:(NSString *)identifier;
+ at end
+ at interface RDar9424890_B : NSObject
+ at end
+ at implementation RDar9424890_B
+- (RDar9424890_A *)obj:(RDar9424890_A *)obj {
+  static NSString *WhizFiz = @"WhizFiz";
+  RDar9424890_A *cell = [obj rdar9424890:WhizFiz];
+  if (cell == ((void*)0)) {
+    cell = [[RDar9424890_A alloc] initWithCleaner:0 mop:WhizFiz]; // no-warning
+  }
+  return cell;
+}
+ at end
+
+// Test that dead store checking works in the prescence of "cleanups" in the AST.
+void rdar9424882() {
+  id x = [NSObject alloc]; // expected-warning {{Value stored to 'x' during its initialization is never read}}
+}
+
+// Test 
+typedef const void *CFTypeRef;
+typedef const struct __CFString *CFStringRef;
+
+ at interface NSString
+- (id) self;
+ at end
+
+CFTypeRef CFCreateSomething();
+CFStringRef CFCreateString();
+CFTypeRef CFGetSomething();
+CFStringRef CFGetString();
+
+id CreateSomething();
+NSString *CreateNSString();
+
+void from_cf() {
+  id obj1 = (__bridge_transfer id)CFCreateSomething(); // expected-warning{{never read}}
+  id obj2 = (__bridge_transfer NSString*)CFCreateString();
+  [obj2 self]; // Add a use, to show we can use the object after it has been transfered.
+  id obj3 = (__bridge id)CFGetSomething();
+  [obj3 self]; // Add a use, to show we can use the object after it has been bridged.
+  id obj4 = (__bridge NSString*)CFGetString(); // expected-warning{{never read}}
+  id obj5 = (__bridge id)CFCreateSomething(); // expected-warning{{never read}} expected-warning{{leak}}
+  id obj6 = (__bridge NSString*)CFCreateString(); // expected-warning{{never read}} expected-warning{{leak}}
+}
+
+void to_cf(id obj) {
+  CFTypeRef cf1 = (__bridge_retained CFTypeRef)CreateSomething(); // expected-warning{{never read}}
+  CFStringRef cf2 = (__bridge_retained CFStringRef)CreateNSString(); // expected-warning{{never read}}
+  CFTypeRef cf3 = (__bridge CFTypeRef)CreateSomething(); // expected-warning{{never read}}
+  CFStringRef cf4 = (__bridge CFStringRef)CreateNSString();  // expected-warning{{never read}}
+}
+
+void test_objc_retainedObject() {
+  CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+  CFDateRef date = CFDateCreate(0, t);
+  id x = objc_retainedObject(date);
+  (void) x;
+}
+
+void test_objc_unretainedObject() {
+  CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+  CFDateRef date = CFDateCreate(0, t);  // expected-warning {{Potential leak}}
+  id x = objc_unretainedObject(date);
+  (void) x;
+}
+

Modified: cfe/trunk/test/Analysis/pr4209.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/pr4209.m?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/pr4209.m (original)
+++ cfe/trunk/test/Analysis/pr4209.m Wed Jun 15 18:02:42 2011
@@ -49,17 +49,17 @@
   GSEbayCategory *rootCategory;
 }
 - (NSMutableDictionary*)categoryDictionaryForCategoryID:(int)inID inRootTreeCategories:(NSMutableArray*)inRootTreeCategories; // expected-note {{method definition for 'categoryDictionaryForCategoryID:inRootTreeCategories:' not found}}
--(NSString*) categoryID;  // expected-note {{method definition for 'categoryID' not found}}
+-(NSString*) categoryID;  // expected-note {{method definition for 'categoryID' not found}} expected-note {{using}}
 @end @interface GSEbayCategory : NSObject <NSCoding> {
 }
-- (int) categoryID;
+- (int) categoryID; // expected-note {{also found}}
 - (GSEbayCategory *) parent;
 - (GSEbayCategory*) subcategoryWithID:(int) inID;
 @end   @implementation GBCategoryChooserPanelController  + (int) chooseCategoryIDFromCategories:(NSArray*) inCategories        searchRequest:(GBSearchRequest*)inRequest         parentWindow:(NSWindow*) inParent { // expected-warning {{incomplete implementation}}
   return 0;
 }
 - (void) addCategory:(EBayCategoryType*)inCategory toRootTreeCategory:(NSMutableArray*)inRootTreeCategories {
-  GSEbayCategory *category = [rootCategory subcategoryWithID:[[inCategory categoryID] intValue]]; 
+  GSEbayCategory *category = [rootCategory subcategoryWithID:[[inCategory categoryID] intValue]]; // expected-warning {{multiple methods named 'categoryID' found}}
 
   if (rootCategory != category)  {
     GSEbayCategory *parent = category;

Added: cfe/trunk/test/CodeGenObjC/arc-arm.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc-arm.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc-arm.m (added)
+++ cfe/trunk/test/CodeGenObjC/arc-arm.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple armv7-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fblocks -fobjc-arc -o - %s | FileCheck %s
+
+id test0(void) {
+  extern id test0_helper(void);
+  // CHECK:      [[T0:%.*]] = call arm_aapcscc i8* @test0_helper()
+  // CHECK-NEXT: ret i8* [[T0]]
+  return test0_helper();
+}
+
+void test1(void) {
+  extern id test1_helper(void);
+  // CHECK:      [[T0:%.*]] = call arm_aapcscc i8* @test1_helper()
+  // CHECK-NEXT: call void asm sideeffect "mov\09r7, r7
+  // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+  // CHECK-NEXT: store i8* [[T1]],
+  // CHECK-NEXT: load
+  // CHECK-NEXT: call void @objc_release
+  // CHECK-NEXT: ret void
+  id x = test1_helper();
+}

Added: cfe/trunk/test/CodeGenObjC/arc-block-ivar-layout.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc-block-ivar-layout.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc-block-ivar-layout.m (added)
+++ cfe/trunk/test/CodeGenObjC/arc-block-ivar-layout.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-nonfragile-abi -triple x86_64-apple-darwin -O0 -emit-llvm %s -o %t-64.s
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// rdar://8991729
+
+__weak id wid;
+void x(id y) {}
+void y(int a) {}
+
+extern id opaque_id();
+
+void f() {
+    __block int byref_int = 0;
+    char ch = 'a';
+    char ch1 = 'b';
+    char ch2 = 'c';
+    short sh = 2;
+    const id bar = (id) opaque_id();
+    id baz = 0;
+    __strong id strong_void_sta;
+    __block id byref_bab = (id)0;
+    __block id bl_var1;
+    int i; double dob;
+
+// The patterns here are a sequence of bytes, each saying first how
+// many sizeof(void*) chunks to skip (high nibble) and then how many
+// to scan (low nibble).  A zero byte says that we've reached the end
+// of the pattern.
+//
+// All of these patterns start with 01 3x because the block header on
+// LP64 consists of an isa pointer (which we're supposed to scan for
+// some reason) followed by three words (2 ints, a function pointer,
+// and a descriptor pointer).
+
+// Test 1
+// byref int, short, char, char, char, id, id, strong id, byref id
+// 01 35 10 00
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [4 x i8] c"\015\10\00"
+    void (^b)() = ^{
+        byref_int = sh + ch+ch1+ch2 ;
+        x(bar);
+        x(baz);
+        x((id)strong_void_sta);
+        x(byref_bab);
+    };    
+    b();
+
+// Test 2
+// byref int, short, char, char, char, id, id, strong id, byref void*, byref id
+// 01 36 10 00
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [4 x i8] c"\016\10\00"
+    void (^c)() = ^{
+        byref_int = sh + ch+ch1+ch2 ;
+        x(bar);
+        x(baz);
+        x((id)strong_void_sta);
+        x(wid);
+        bl_var1 = 0;
+        x(byref_bab);
+    };    
+}

Added: cfe/trunk/test/CodeGenObjC/arc-bridged-cast.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc-bridged-cast.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc-bridged-cast.m (added)
+++ cfe/trunk/test/CodeGenObjC/arc-bridged-cast.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,90 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fblocks -fobjc-arc -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+
+typedef const void *CFTypeRef;
+typedef const struct __CFString *CFStringRef;
+
+ at interface NSString
+ at end
+
+CFTypeRef CFCreateSomething(void);
+CFStringRef CFCreateString(void);
+CFTypeRef CFGetSomething(void);
+CFStringRef CFGetString(void);
+
+id CreateSomething(void);
+NSString *CreateNSString(void);
+
+// CHECK: define void @bridge_transfer_from_cf
+void bridge_transfer_from_cf(int *i) {
+  // CHECK: store i32 7
+  *i = 7;
+  // CHECK: call i8* @CFCreateSomething()
+  id obj1 = (__bridge_transfer id)CFCreateSomething();
+  // CHECK-NOT: retain
+  // CHECK: store i32 11
+  *i = 11;
+  // CHECK: call i8* @CFCreateSomething()
+  // CHECK-NOT: retain
+  // CHECK: store i32 13
+  (void)(__bridge_transfer id)CFCreateSomething(), *i = 13;
+  // CHECK: call void @objc_release
+  // CHECK: store i32 17
+  *i = 17;
+  // CHECK: call void @objc_release
+  // CHECK-NEXT: ret void
+}
+
+// CHECK: define void @bridge_from_cf
+void bridge_from_cf(int *i) {
+  // CHECK: store i32 7
+  *i = 7;
+  // CHECK: call i8* @CFCreateSomething()
+  id obj1 = (__bridge id)CFCreateSomething();
+  // CHECK: objc_retainAutoreleasedReturnValue
+  // CHECK: store i32 11
+  *i = 11;
+  // CHECK: call i8* @CFCreateSomething()
+  // CHECK-NOT: release
+  // CHECK: store i32 13
+  (void)(__bridge id)CFCreateSomething(), *i = 13;
+  // CHECK: store i32 17
+  *i = 17;
+  // CHECK: call void @objc_release
+  // CHECK-NEXT: ret void
+}
+
+// CHECK: define void @bridge_retained_of_cf
+void bridge_retained_of_cf(int *i) {
+  *i = 7;
+  // CHECK: call i8* @CreateSomething()
+  CFTypeRef cf1 = (__bridge_retained CFTypeRef)CreateSomething();
+  // CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue
+  // CHECK: store i32 11
+  *i = 11;
+  // CHECK: call i8* @CreateSomething()
+  (__bridge_retained CFTypeRef)CreateSomething(), *i = 13;
+  // CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue
+  // CHECK: store i32 13
+  // CHECK: store i32 17
+  *i = 17;
+  // CHECK-NEXT: ret void
+}
+
+// CHECK: define void @bridge_of_cf
+void bridge_of_cf(int *i) {
+  // CHECK: store i32 7
+  *i = 7;
+  // CHECK: call i8* @CreateSomething()
+  CFTypeRef cf1 = (__bridge CFTypeRef)CreateSomething();
+  // CHECK-NOT: retain
+  // CHECK: store i32 11
+  *i = 11;
+  // CHECK: call i8* @CreateSomething
+  (__bridge CFTypeRef)CreateSomething(), *i = 13;
+  // CHECK: store i32 13
+  // CHECK-NOT: release
+  // CHECK: store i32 17
+  *i = 17;
+  // CHECK-NEXT: ret void
+}
+

Added: cfe/trunk/test/CodeGenObjC/arc-foreach.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc-foreach.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc-foreach.m (added)
+++ cfe/trunk/test/CodeGenObjC/arc-foreach.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-nonfragile-abi -triple x86_64-apple-darwin -O0 -emit-llvm %s -o %t-64.s
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// rdar://9503326
+
+typedef void (^dispatch_block_t)(void);
+
+ at class NSString;
+extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
+ at class NSArray;
+
+int main (int argc, const char * argv[])
+{
+    NSArray *array;
+    for ( NSString *str in array) {
+        dispatch_block_t blk = ^{
+            NSLog(@"str in block: %@", str);
+        };
+        blk();
+    }
+    return 0;
+}
+
+// CHECK-LP64: define internal void @__main_block_invoke
+// CHECK-LP64: [[BLOCK:%.*]] = bitcast i8* {{%.*}} to [[BLOCK_T:%.*]]*
+// CHECK-LP64-NEXT: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+// CHECK-LP64-NEXT: [[T2:%.*]] = load [[OPAQUE_T:%.*]]** [[T0]], align 8 
+// CHECK-LP64-NEXT: call void ([[OPAQUE_T]]*, ...)* @NSLog

Added: cfe/trunk/test/CodeGenObjC/arc-ivar-layout.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc-ivar-layout.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc-ivar-layout.m (added)
+++ cfe/trunk/test/CodeGenObjC/arc-ivar-layout.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -fobjc-arc -fobjc-nonfragile-abi -triple x86_64-apple-darwin -O0 -S %s -o %t-64.s
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// rdar://8991729
+
+ at interface NSObject {
+  id isa;
+}
+ at end
+
+ at interface AllPointers : NSObject {
+    id foo;
+    id __strong bar;    
+    NSObject *bletch;
+}
+ at end
+
+ at implementation AllPointers
+ at end
+// CHECK-LP64: L_OBJC_CLASS_NAME_1:
+// CHECK-LP64-NEXT: .asciz	"\003"
+
+ at class NSString, NSNumber;
+ at interface A : NSObject {
+   NSString *foo;
+   NSNumber *bar;
+   unsigned int bletch;
+   __weak id delegate;
+}
+ at end
+
+ at interface B : A {
+  unsigned int x;
+  NSString *y;
+  NSString *z;
+}
+ at end
+
+ at implementation A @end
+
+ at implementation B @end
+
+// CHECK-LP64: L_OBJC_CLASS_NAME_15:
+// CHECK-LP64-NEXT: .asciz	"\022"
+

Added: cfe/trunk/test/CodeGenObjC/arc-no-runtime.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc-no-runtime.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc-no-runtime.m (added)
+++ cfe/trunk/test/CodeGenObjC/arc-no-runtime.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-arc -fobjc-nonfragile-abi -fobjc-no-arc-runtime -emit-llvm %s -o - | FileCheck %s
+
+// rdar://problem/9224855
+void test0() {
+  id x = 0;
+  // CHECK: call void @objc_release(
+}
+
+// CHECK: declare extern_weak void @objc_release(

Added: cfe/trunk/test/CodeGenObjC/arc-related-result-type.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc-related-result-type.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc-related-result-type.m (added)
+++ cfe/trunk/test/CodeGenObjC/arc-related-result-type.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fblocks -fobjc-arc -o - %s | FileCheck %s
+
+ at interface Test0
+- (id) self;
+ at end
+void test0(Test0 *val) {
+  Test0 *x = [val self];
+
+// CHECK:    define void @test0(
+// CHECK:      [[VAL:%.*]] = alloca [[TEST0:%.*]]*
+// CHECK-NEXT: [[X:%.*]] = alloca [[TEST0]]*
+// CHECK-NEXT: bitcast
+// CHECK-NEXT: call i8* @objc_retain(
+// CHECK-NEXT: bitcast
+// CHECK-NEXT: store
+// CHECK-NEXT: load [[TEST0]]** [[VAL]],
+// CHECK-NEXT: load
+// CHECK-NEXT: bitcast
+// CHECK-NEXT: [[T0:%.*]] = call i8* bitcast (
+// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to [[TEST0]]*
+// CHECK-NEXT: store [[TEST0]]* [[T2]], [[TEST0]]** [[X]]
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST0]]** [[X]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST0]]* [[T0]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T1]])
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST0]]** [[VAL]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST0]]* [[T0]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T1]])
+// CHECK-NEXT: ret void
+}

Added: cfe/trunk/test/CodeGenObjC/arc-unopt.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc-unopt.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc-unopt.m (added)
+++ cfe/trunk/test/CodeGenObjC/arc-unopt.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,69 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fblocks -fobjc-arc -o - %s | FileCheck %s
+
+// A test to ensure that we generate fused calls at -O0.
+
+ at class Test0;
+Test0 *test0(void) {
+  extern Test0 *test0_helper;
+  return test0_helper;
+
+  // CHECK:      [[LD:%.*]] = load [[TEST0:%.*]]** @test0_helper
+  // CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST0]]* [[LD]] to i8*
+  // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleaseReturnValue(i8* [[T0]])
+  // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to [[TEST0]]*
+  // CHECK-NEXT: ret [[TEST0]]* [[T2]]
+}
+
+id test1(void) {
+  extern id test1_helper;
+  return test1_helper;
+
+  // CHECK:      [[LD:%.*]] = load i8** @test1_helper
+  // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retainAutoreleaseReturnValue(i8* [[LD]])
+  // CHECK-NEXT: ret i8* [[T0]]
+}
+
+void test2(void) {
+  // CHECK:      [[X:%.*]] = alloca i8*
+  // CHECK-NEXT: store i8* null, i8** [[X]]
+  // CHECK-NEXT: call void @objc_destroyWeak(i8** [[X]])
+  // CHECK-NEXT: ret void
+  __weak id x;
+}
+
+id test3(void) {
+  extern id test3_helper(void);
+  // CHECK:      [[T0:%.*]] = call i8* @test3_helper()
+  // CHECK-NEXT: ret i8* [[T0]]
+  return test3_helper();
+}
+
+ at interface Test4 { id x; } @end
+ at interface Test4_sub : Test4 { id y; } @end
+Test4 *test4(void) {
+  extern Test4_sub *test4_helper(void);
+  // CHECK:      [[T0:%.*]] = call [[TEST4S:%.*]]* @test4_helper()
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST4S]]* [[T0]] to [[TEST4:%.*]]*
+  // CHECK-NEXT: ret [[TEST4]]* [[T1]]
+  return test4_helper();
+}
+
+// rdar://problem/9418404
+ at class Test5;
+void test5(void) {
+  Test5 *x, *y;
+  if ((x = y))
+    y = 0;
+
+// CHECK:    define void @test5()
+// CHECK:      [[X:%.*]] = alloca [[TEST5:%.*]]*,
+// CHECK-NEXT: [[Y:%.*]] = alloca [[TEST5:%.*]]*,
+// CHECK-NEXT: store [[TEST5]]* null, [[TEST5]]** [[X]],
+// CHECK-NEXT: store [[TEST5]]* null, [[TEST5]]** [[Y]],
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST5]]** [[Y]],
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST5]]** [[X]] to i8**
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST5]]* [[T0]] to i8*
+// CHECK-NEXT: call void @objc_storeStrong(i8** [[T1]], i8* [[T2]])
+// CHECK-NEXT: [[T3:%.*]] = icmp ne [[TEST5]]* [[T0]], null
+// CHECK-NEXT: br i1 [[T3]],
+}

Added: cfe/trunk/test/CodeGenObjC/arc-weak-property.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc-weak-property.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc-weak-property.m (added)
+++ cfe/trunk/test/CodeGenObjC/arc-weak-property.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fblocks -fobjc-arc -o - %s | FileCheck %s
+// rdar://8899430
+
+ at interface WeakPropertyTest {
+    __weak id PROP;
+}
+ at property () __weak id PROP;
+ at end
+
+ at implementation WeakPropertyTest
+ at synthesize PROP;
+ at end
+
+// CHECK:     define internal i8* @"\01-[WeakPropertyTest PROP]"
+// CHECK:       [[SELF:%.*]] = alloca [[WPT:%.*]]*,
+// CHECK-NEXT:  [[CMD:%.*]] = alloca i8*,
+// CHECK-NEXT:  store [[WPT]]* {{%.*}}, [[WPT]]** [[SELF]]
+// CHECK-NEXT:  store i8* {{%.*}}, i8** [[CMD]]
+// CHECK-NEXT:  [[T0:%.*]] = load [[WPT]]** [[SELF]]
+// CHECK-NEXT:  [[T1:%.*]] = load i64* @"OBJC_IVAR_$_WeakPropertyTest.PROP"
+// CHECK-NEXT:  [[T2:%.*]] = bitcast [[WPT]]* [[T0]] to i8*
+// CHECK-NEXT:  [[T3:%.*]] = getelementptr inbounds i8* [[T2]], i64 [[T1]]
+// CHECK-NEXT:  [[T4:%.*]] = bitcast i8* [[T3]] to i8**
+// CHECK-NEXT:  [[T5:%.*]] = call i8* @objc_loadWeakRetained(i8** [[T4]])
+// CHECK-NEXT:  [[T6:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T5]])
+// CHECK-NEXT:  ret i8* [[T6]]
+
+// CHECK:     define internal void @"\01-[WeakPropertyTest setPROP:]"
+// CHECK:       [[SELF:%.*]] = alloca [[WPT:%.*]]*,
+// CHECK-NEXT:  [[CMD:%.*]] = alloca i8*,
+// CHECK-NEXT:  [[PROP:%.*]] = alloca i8*,
+// CHECK-NEXT:  store [[WPT]]* {{%.*}}, [[WPT]]** [[SELF]]
+// CHECK-NEXT:  store i8* {{%.*}}, i8** [[CMD]]
+// CHECK-NEXT:  store i8* {{%.*}}, i8** [[PROP]]
+// CHECK-NEXT:  [[V:%.*]] = load i8** [[PROP]]
+// CHECK-NEXT:  [[T0:%.*]] = load [[WPT]]** [[SELF]]
+// CHECK-NEXT:  [[T1:%.*]] = load i64* @"OBJC_IVAR_$_WeakPropertyTest.PROP"
+// CHECK-NEXT:  [[T2:%.*]] = bitcast [[WPT]]* [[T0]] to i8*
+// CHECK-NEXT:  [[T3:%.*]] = getelementptr inbounds i8* [[T2]], i64 [[T1]]
+// CHECK-NEXT:  [[T4:%.*]] = bitcast i8* [[T3]] to i8**
+// CHECK-NEXT:  call i8* @objc_storeWeak(i8** [[T4]], i8* [[V]])
+// CHECK-NEXT:  ret void
+
+// CHECK:     define internal void @"\01-[WeakPropertyTest .cxx_destruct]"
+// CHECK:       [[SELF:%.*]] = alloca [[WPT:%.*]]*,
+// CHECK-NEXT:  [[CMD:%.*]] = alloca i8*,
+// CHECK-NEXT:  store [[WPT]]* {{%.*}}, [[WPT]]** [[SELF]]
+// CHECK-NEXT:  store i8* {{%.*}}, i8** [[CMD]]
+// CHECK-NEXT:  [[T0:%.*]] = load [[WPT]]** [[SELF]]
+// CHECK-NEXT:  [[T1:%.*]] = load i64* @"OBJC_IVAR_$_WeakPropertyTest.PROP"
+// CHECK-NEXT:  [[T2:%.*]] = bitcast [[WPT]]* [[T0]] to i8*
+// CHECK-NEXT:  [[T3:%.*]] = getelementptr inbounds i8* [[T2]], i64 [[T1]]
+// CHECK-NEXT:  [[T4:%.*]] = bitcast i8* [[T3]] to i8**
+// CHECK-NEXT:  call void @objc_destroyWeak(i8** [[T4]])
+// CHECK-NEXT:  ret void

Added: cfe/trunk/test/CodeGenObjC/arc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc.m (added)
+++ cfe/trunk/test/CodeGenObjC/arc.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,1511 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fblocks -fobjc-arc -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fblocks -fobjc-arc -o - %s | FileCheck -check-prefix=CHECK-GLOBALS %s
+
+// CHECK: define void @test0
+void test0(id x) {
+  // CHECK:      [[X:%.*]] = alloca i8*
+  // CHECK-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{.*}})
+  // CHECK-NEXT: store i8* [[PARM]], i8** [[X]]
+  // CHECK-NEXT: [[TMP:%.*]] = load i8** [[X]]
+  // CHECK-NEXT: call void @objc_release(i8* [[TMP]])
+  // CHECK-NEXT: ret void
+}
+
+// CHECK: define i8* @test1(i8*
+id test1(id x) {
+  // CHECK:      [[RET:%.*]] = alloca i8*
+  // CHECK-NEXT: [[X:%.*]] = alloca i8*
+  // CHECK-NEXT: [[Y:%.*]] = alloca i8*
+  // CHECK-NEXT: alloca i32
+  // CHECK-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{%.*}})
+  // CHECK-NEXT: store i8* [[PARM]], i8** [[X]]
+  // CHECK-NEXT: store i8* null, i8** [[Y]]
+  // CHECK-NEXT: [[T0:%.*]] = load i8** [[Y]]
+  // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
+  // CHECK-NEXT: store i8* [[T1]], i8** [[RET]]
+  // CHECK-NEXT: store i32
+  // CHECK-NEXT: [[T0:%.*]] = load i8** [[Y]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+  // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+  // CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]]
+  // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T0]])
+  // CHECK-NEXT: ret i8* [[T1]]
+  id y;
+  return y;
+}
+
+ at interface Test2
++ (void) class_method;
+- (void) inst_method;
+ at end
+ at implementation Test2
+
+// The self pointer of a class method is not retained.
+// CHECK: define internal void @"\01+[Test2 class_method]"
+// CHECK:      alloca
+// CHECK-NEXT: alloca
+// CHECK-NEXT: store
+// CHECK-NEXT: store
+// CHECK-NEXT: ret void
++ (void) class_method {}
+
+// The self pointer of an instance method is not retained.
+// CHECK: define internal void @"\01-[Test2 inst_method]"
+// CHECK:      alloca
+// CHECK-NEXT: alloca
+// CHECK-NEXT: store
+// CHECK-NEXT: store
+// CHECK-NEXT: ret void
+- (void) inst_method {}
+ at end
+
+ at interface Test3
++ (id) alloc;
+- (id) initWith: (int) x;
+- (id) copy;
+ at end
+
+// CHECK: define void @test3_unelided()
+void test3_unelided() {
+  extern void test3_helper(void);
+
+  // CHECK:      [[X:%.*]] = alloca [[TEST3:%.*]]*
+  // CHECK-NEXT: store [[TEST3]]* null, [[TEST3]]** [[X]], align
+  Test3 *x;
+
+  // Call to +alloc.
+  // CHECK-NEXT: load {{.*}}* @"\01L_OBJC_CLASSLIST_REFERENCES_
+  // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: [[ALLOC:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: call void @objc_release(i8*
+  [Test3 alloc];
+
+  // CHECK-NEXT: [[T0:%.*]] = load [[TEST3]]** [[X]]
+  // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST3]]* [[T0]] to i8*
+  // CHECK-NEXT: [[COPY:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend {{.*}})(i8* [[T1]],
+  // CHECK-NEXT: call void @objc_release(i8* [[COPY]]) nounwind
+  [x copy];
+
+  // CHECK-NEXT: [[T0:%.*]] = load [[TEST3]]** [[X]]
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST3]]* [[T0]] to i8*
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind
+  // CHECK-NEXT: ret void
+}
+
+// CHECK: define void @test3()
+void test3() {
+  // CHECK:      [[X:%.*]] = alloca i8*
+
+  id x = [[Test3 alloc] initWith: 5];
+
+  // Call to +alloc.
+  // CHECK-NEXT: load {{.*}}* @"\01L_OBJC_CLASSLIST_REFERENCES_
+  // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: [[ALLOC:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+  // CHECK-NEXT: bitcast
+
+  // Call to -initWith: with elided retain of consumed argument.
+  // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: [[INIT:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*, i32)*)(i8* 
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: [[INIT:%.*]] = bitcast
+  // Assignment for initialization, retention elided.
+  // CHECK-NEXT: store i8* [[INIT]], i8** [[X]]
+
+  // Call to -copy.
+  // CHECK-NEXT: [[V:%.*]] = load i8** [[X]]
+  // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+  // CHECK-NEXT: [[COPY:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend {{.*}})(i8* [[V]],
+
+  // Assignment to x.
+  // CHECK-NEXT: [[TMP:%.*]] = load i8** [[X]]
+  // CHECK-NEXT: store i8* [[COPY]], i8** [[X]]
+  // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) nounwind
+
+  x = [x copy];
+
+  // Cleanup for x.
+  // CHECK-NEXT: [[TMP:%.*]] = load i8** [[X]]
+  // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) nounwind
+  
+  // CHECK-NEXT: ret void
+}
+
+// CHECK: define i8* @test4()
+id test4() {
+  // Call to +alloc.
+  // CHECK:      load {{.*}}* @"\01L_OBJC_CLASSLIST_REFERENCES_
+  // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: [[ALLOC:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+  // CHECK-NEXT: [[ALLOC:%.*]] = bitcast
+
+  // Call to -initWith: with elided retain of consumed argument.
+  // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+  // CHECK-NEXT: [[ALLOC:%.*]] = bitcast
+  // CHECK-NEXT: [[INIT:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*, i32)*)(i8* [[ALLOC]],
+
+  // Initialization of return value, occuring within full-expression.
+  // Retain/release elided.
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: [[INIT:%.*]] = bitcast
+  // CHECK-NEXT: [[RET:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[INIT]])
+
+  // CHECK-NEXT: ret i8* [[RET]]
+
+  return [[Test3 alloc] initWith: 6];
+}
+
+ at interface Test5 {
+ at public
+  id var;
+}
+ at end
+
+// CHECK: define void @test5
+void test5(Test5 *x, id y) {
+  // Prologue.
+  // CHECK:      [[X:%.*]] = alloca [[TEST5:%.*]]*,
+  // CHECK-NEXT: [[Y:%.*]] = alloca i8*
+  // CHECK-NEXT: bitcast [[TEST5]]* {{%.*}} to i8*
+  // CHECK-NEXT: call i8* @objc_retain
+  // CHECK-NEXT: [[PARMX:%.*]] = bitcast i8* {{%.*}} to [[TEST5]]*
+  // CHECK-NEXT: store [[TEST5]]* [[PARMX]], [[TEST5]]** [[X]]
+  // CHECK-NEXT: call i8* @objc_retain
+  // CHECK-NEXT: store
+
+  // CHECK-NEXT: load [[TEST5]]** [[X]]
+  // CHECK-NEXT: load i64* @"OBJC_IVAR_$_Test5.var"
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: getelementptr
+  // CHECK-NEXT: [[VAR:%.*]] = bitcast
+  // CHECK-NEXT: [[TMP:%.*]] = load i8** [[VAR]]
+  // CHECK-NEXT: store i8* null, i8** [[VAR]]
+  // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) nounwind
+  x->var = 0;
+
+  // CHECK-NEXT: [[YVAL:%.*]] = load i8** [[Y]]
+  // CHECK-NEXT: load [[TEST5]]** [[X]]
+  // CHECK-NEXT: load i64* @"OBJC_IVAR_$_Test5.var"
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: getelementptr
+  // CHECK-NEXT: [[VAR:%.*]] = bitcast
+  // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* [[YVAL]]) nounwind
+  // CHECK-NEXT: [[TMP:%.*]] = load i8** [[VAR]]
+  // CHECK-NEXT: store i8* [[T0]], i8** [[VAR]]
+  // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) nounwind
+  x->var = y;
+
+  // Epilogue.
+  // CHECK-NEXT: [[TMP:%.*]] = load i8** [[Y]]
+  // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) nounwind
+  // CHECK-NEXT: [[T0:%.*]] = load [[TEST5]]** [[X]]
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST5]]* [[T0]] to i8*
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind
+  // CHECK-NEXT: ret void
+}
+
+id test6_helper(void) __attribute__((ns_returns_retained));
+// CHECK: define void @test6()
+void test6() {
+  // CHECK:      [[X:%.*]] = alloca i8*
+  // CHECK-NEXT: [[CALL:%.*]] = call i8* @test6_helper()
+  // CHECK-NEXT: store i8* [[CALL]], i8** [[X]]
+  // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release
+  // CHECK-NEXT: ret void
+  id x = test6_helper();
+}
+
+void test7_helper(id __attribute__((ns_consumed)));
+// CHECK: define void @test7()
+void test7() {
+  // CHECK:      [[X:%.*]] = alloca i8*
+  // CHECK-NEXT: store i8* null, i8** [[X]]
+  // CHECK-NEXT: [[T0:%.*]] = load i8** [[X]]
+  // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) nounwind
+  // CHECK-NEXT: call void @test7_helper(i8* [[T1]])
+  // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release
+  // CHECK-NEXT: ret void
+  id x;
+  test7_helper(x);
+}
+
+id test8_helper(void) __attribute__((ns_returns_retained));
+void test8() {
+  __unsafe_unretained id x = test8_helper();
+  // CHECK:      [[X:%.*]] = alloca i8*
+  // CHECK-NEXT: [[T0:%.*]] = call i8* @test8_helper()
+  // CHECK-NEXT: store i8* [[T0]], i8** [[X]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind
+  // CHECK-NOT:  imprecise_release
+  // CHECK-NEXT: ret void
+}
+
+id test9_helper(void) __attribute__((ns_returns_retained));
+void test9() {
+  id x __attribute__((objc_precise_lifetime)) = test9_helper();
+  x = 0;
+  // CHECK:      [[X:%.*]] = alloca i8*
+  // CHECK-NEXT: [[CALL:%.*]] = call i8* @test9_helper()
+  // CHECK-NEXT: store i8* [[CALL]], i8** [[X]]
+
+  // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
+  // CHECK-NEXT: store i8* null, i8** [[X]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release
+
+  // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind
+  // CHECK-NOT:  clang.imprecise_release
+
+  // CHECK-NEXT: ret void
+}
+
+ at interface Test10
+ at property (retain) Test10 *me;
+ at end
+void test10() {
+  Test10 *x;
+  id y = x.me.me;
+
+  // CHECK:      define void @test10()
+  // CHECK:      [[X:%.*]] = alloca [[TEST10:%.*]]*, align
+  // CHECK-NEXT: [[Y:%.*]] = alloca i8*, align
+  // CHECK-NEXT: store [[TEST10]]* null, [[TEST10]]** [[X]]
+  // CHECK-NEXT: load [[TEST10]]** [[X]], align
+  // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_{{[0-9]*}}"
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: call [[TEST10]]* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+  // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_{{[0-9]*}}"
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: [[T0:%.*]] = call [[TEST10]]* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST10]]* [[T0]] to i8*
+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST10]]*
+  // CHECK-NEXT: [[T4:%.*]] = bitcast [[TEST10]]* [[T3]] to i8*
+  // CHECK-NEXT: store i8* [[T4]], i8** [[Y]]
+  // CHECK-NEXT: [[T0:%.*]] = load i8** [[Y]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+  // CHECK-NEXT: [[T0:%.*]] = load [[TEST10]]** [[X]]
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST10]]* [[T0]] to i8*
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+  // CHECK-NEXT: ret void
+}
+
+void test11(id (*f)(void) __attribute__((ns_returns_retained))) {
+  // CHECK:      define void @test11(
+  // CHECK:      [[F:%.*]] = alloca i8* ()*, align
+  // CHECK-NEXT: [[X:%.*]] = alloca i8*, align
+  // CHECK-NEXT: store i8* ()* {{%.*}}, i8* ()** [[F]], align
+  // CHECK-NEXT: [[T0:%.*]] = load i8* ()** [[F]], align
+  // CHECK-NEXT: [[T1:%.*]] = call i8* [[T0]]()
+  // CHECK-NEXT: store i8* [[T1]], i8** [[X]], align
+  // CHECK-NEXT: [[T3:%.*]] = load i8** [[X]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T3]]) nounwind, !clang.imprecise_release
+  // CHECK-NEXT: ret void
+  id x = f();
+}
+
+void test12(void) {
+  extern id test12_helper(void);
+
+  // CHECK:      define void @test12()
+  // CHECK:      [[X:%.*]] = alloca i8*, align
+  // CHECK-NEXT: [[Y:%.*]] = alloca i8*, align
+
+  __weak id x = test12_helper();
+  // CHECK-NEXT: [[T0:%.*]] = call i8* @test12_helper()
+  // CHECK-NEXT: call i8* @objc_initWeak(i8** [[X]], i8* [[T0]])
+
+  x = test12_helper();
+  // CHECK-NEXT: [[T1:%.*]] = call i8* @test12_helper()
+  // CHECK-NEXT: call i8* @objc_storeWeak(i8** [[X]], i8* [[T1]])
+
+  id y = x;
+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_loadWeakRetained(i8** [[X]])
+  // CHECK-NEXT: store i8* [[T2]], i8** [[Y]], align
+
+  // CHECK-NEXT: [[T4:%.*]] = load i8** [[Y]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T4]]) nounwind, !clang.imprecise_release
+  // CHECK-NEXT: call void @objc_destroyWeak(i8** [[X]])
+  // CHECK-NEXT: ret void
+}
+
+// Indirect consuming calls.
+void test13(void) {
+  // CHECK:      define void @test13()
+  // CHECK:      [[X:%.*]] = alloca i8*, align
+  // CHECK-NEXT: store i8* null, i8** [[X]], align
+  id x;
+
+  typedef void fnty(id __attribute__((ns_consumed)));
+  extern fnty *test13_func;
+  // CHECK-NEXT: [[FN:%.*]] = load void (i8*)** @test13_func, align
+  // CHECK-NEXT: [[X_VAL:%.*]] = load i8** [[X]], align
+  // CHECK-NEXT: [[X_TMP:%.*]] = call i8* @objc_retain(i8* [[X_VAL]]) nounwind
+  // CHECK-NEXT: call void [[FN]](i8* [[X_TMP]])
+  test13_func(x);
+
+  extern fnty ^test13_block;
+  // CHECK-NEXT: [[TMP:%.*]] = load void (i8*)** @test13_block, align
+  // CHECK-NEXT: [[BLOCK:%.*]] = bitcast void (i8*)* [[TMP]] to [[BLOCKTY:%.*]]*
+  // CHECK-NEXT: [[BLOCK_FN_PTR:%.*]] = getelementptr inbounds [[BLOCKTY]]* [[BLOCK]], i32 0, i32 3
+  // CHECK-NEXT: [[BLOCK_OPAQUE:%.*]] = bitcast [[BLOCKTY]]* [[BLOCK]] to i8*
+  // CHECK-NEXT: [[X_VAL:%.*]] = load i8** [[X]], align
+  // CHECK-NEXT: [[X_TMP:%.*]] = call i8* @objc_retain(i8* [[X_VAL]]) nounwind
+  // CHECK-NEXT: [[BLOCK_FN_TMP:%.*]] = load i8** [[BLOCK_FN_PTR]]
+  // CHECK-NEXT: [[BLOCK_FN:%.*]] = bitcast i8* [[BLOCK_FN_TMP]] to void (i8*, i8*)*
+  // CHECK-NEXT: call void [[BLOCK_FN]](i8* [[BLOCK_OPAQUE]], i8* [[X_TMP]])
+  test13_block(x);
+
+  // CHECK-NEXT: [[T0:%.*]] = load i8** [[X]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind
+  // CHECK-NEXT: ret void
+}
+
+ at interface Test16_super @end
+ at interface Test16 : Test16_super {
+  id z;
+}
+ at property (assign) int x;
+ at property (retain) id y;
+- (void) dealloc;
+ at end
+ at implementation Test16
+ at synthesize x;
+ at synthesize y;
+- (void) dealloc {
+  // CHECK:    define internal void @"\01-[Test16 dealloc]"(
+  // CHECK:      [[SELF:%.*]] = alloca [[TEST16:%.*]]*, align
+  // CHECK-NEXT: [[CMD:%.*]] = alloca i8*, align
+  // CHECK-NEXT: alloca
+  // CHECK-NEXT: store [[TEST16]]* {{%.*}}, [[TEST16]]** [[SELF]], align
+  // CHECK-NEXT: store i8* {{%.*}}, i8** [[CMD]]
+  // CHECK-NEXT: [[BASE:%.*]] = load [[TEST16]]** [[SELF]]
+
+  // Call super.
+  // CHECK-NEXT: [[BASE2:%.*]] = bitcast [[TEST16]]* [[BASE]] to i8*
+  // CHECK-NEXT: [[T0:%.*]] = getelementptr
+  // CHECK-NEXT: store i8* [[BASE2]], i8** [[T0]]
+  // CHECK-NEXT: load {{%.*}}** @"\01L_OBJC_CLASSLIST_SUP_REFS_$_
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: getelementptr
+  // CHECK-NEXT: store
+  // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+  // CHECK-NEXT: call void bitcast (i8* ({{.*}})* @objc_msgSendSuper2 to void (
+  // CHECK-NEXT: ret void
+}
+
+// .cxx_destruct
+  // CHECK:    define internal void @"\01-[Test16 .cxx_destruct]"(
+  // CHECK:      [[SELF:%.*]] = alloca [[TEST16:%.*]]*, align
+  // CHECK-NEXT: [[CMD:%.*]] = alloca i8*, align
+  // CHECK-NEXT: store [[TEST16]]* {{%.*}}, [[TEST16]]** [[SELF]], align
+  // CHECK-NEXT: store i8* {{%.*}}, i8** [[CMD]]
+  // CHECK-NEXT: [[BASE:%.*]] = load [[TEST16]]** [[SELF]]
+
+  // Destroy y.
+  // CHECK-NEXT: [[Y_OFF:%.*]] = load i64* @"OBJC_IVAR_$_Test16.y"
+  // CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST16]]* [[BASE]] to i8*
+  // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8* [[T0]], i64 [[Y_OFF]]
+  // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to i8**
+  // CHECK-NEXT: call void @objc_storeStrong(i8** [[T2]], i8* null) nounwind
+
+  // Destroy z.
+  // CHECK-NEXT: [[Z_OFF:%.*]] = load i64* @"OBJC_IVAR_$_Test16.z"
+  // CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST16]]* [[BASE]] to i8*
+  // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8* [[T0]], i64 [[Z_OFF]]
+  // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to i8**
+  // CHECK-NEXT: call void @objc_storeStrong(i8** [[T2]], i8* null) nounwind
+
+  // CHECK-NEXT: ret void
+
+ at end
+
+// This shouldn't crash.
+ at interface Test17A
+ at property (assign) int x;
+ at end
+ at interface Test17B : Test17A
+ at end
+ at implementation Test17B
+- (int) x { return super.x + 1; }
+ at end
+
+// This shouldn't crash.
+void test18(id (^maker)(void)) {
+  maker();
+}
+
+void test19() {
+  // CHECK: define void @test19()
+  // CHECK:      [[X:%.*]] = alloca [5 x i8*], align 16
+  // CHECK-NEXT: [[T0:%.*]] = bitcast [5 x i8*]* [[X]] to i8*
+  // CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 40, i32 16, i1 false)
+  id x[5];
+
+  extern id test19_helper(void);
+  x[2] = test19_helper();
+
+  // CHECK-NEXT: [[CALL:%.*]] = call i8* @test19_helper()
+  // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[CALL]]) nounwind
+  // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [5 x i8*]* [[X]], i32 0, i64 2
+  // CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]]
+  // CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind
+
+  // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [5 x i8*]* [[X]], i32 0, i32 0
+  // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds i8** [[BEGIN]], i64 5
+  // CHECK-NEXT: br label
+
+  // CHECK:      [[CUR:%.*]] = phi i8**
+  // CHECK-NEXT: [[EQ:%.*]] = icmp eq i8** [[CUR]], [[END]]
+  // CHECK-NEXT: br i1 [[EQ]],
+
+  // CHECK:      [[T0:%.*]] = load i8** [[CUR]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
+  // CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds i8** [[CUR]], i32 1
+  // CHECK-NEXT: br label
+
+  // CHECK:      ret void
+}
+
+void test20(unsigned n) {
+  // CHECK: define void @test20
+  // CHECK:      [[N:%.*]] = alloca i32, align 4
+  // CHECK-NEXT: [[SAVED_STACK:%.*]] = alloca i8*
+  // CHECK-NEXT: store i32 {{%.*}}, i32* [[N]], align 4
+
+  id x[n];
+
+  // Capture the VLA size.
+  // CHECK-NEXT: [[T0:%.*]] = call i8* @llvm.stacksave()
+  // CHECK-NEXT: store i8* [[T0]], i8** [[SAVED_STACK]]
+  // CHECK-NEXT: [[T0:%.*]] = load i32* [[N]], align 4
+  // CHECK-NEXT: [[T1:%.*]] = zext i32 [[T0]] to i64
+  // CHECK-NEXT: [[VLA_SIZE:%.*]] = mul i64 8, [[T1]]
+
+  // Allocate the VLA.
+  // CHECK-NEXT: [[T0:%.*]] = alloca i8, i64 [[VLA_SIZE]], align 16
+  // CHECK-NEXT: [[VLA:%.*]] = bitcast i8* [[T0]] to i8**
+
+  // Zero-initialize.
+  // CHECK-NEXT: [[T0:%.*]] = bitcast i8** [[VLA]] to i8*
+  // CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 [[VLA_SIZE]], i32 8, i1 false)
+
+  // Destroy.
+  // CHECK-NEXT: [[VLA_COUNT:%.*]] = udiv i64 [[VLA_SIZE]], 8
+  // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds i8** [[VLA]], i64 [[VLA_COUNT]]
+  // CHECK-NEXT: br label
+
+  // CHECK:      [[CUR:%.*]] = phi i8**
+  // CHECK-NEXT: [[EQ:%.*]] = icmp eq i8** [[CUR]], [[END]]
+  // CHECK-NEXT: br i1 [[EQ]],
+
+  // CHECK:      [[T0:%.*]] = load i8** [[CUR]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
+  // CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds i8** [[CUR]], i32 1
+  // CHECK-NEXT: br label
+
+  // CHECK:      [[T0:%.*]] = load i8** [[SAVED_STACK]]
+  // CHECK-NEXT: call void @llvm.stackrestore(i8* [[T0]])
+  // CHECK-NEXT: ret void
+}
+
+void test21(unsigned n) {
+  // CHECK: define void @test21
+  // CHECK:      [[N:%.*]] = alloca i32, align 4
+  // CHECK-NEXT: [[SAVED_STACK:%.*]] = alloca i8*
+  // CHECK-NEXT: store i32 {{%.*}}, i32* [[N]], align 4
+
+  id x[2][n][3];
+
+  // Capture the VLA size.
+  // CHECK-NEXT: [[T0:%.*]] = call i8* @llvm.stacksave()
+  // CHECK-NEXT: store i8* [[T0]], i8** [[SAVED_STACK]]
+  // CHECK-NEXT: [[T0:%.*]] = load i32* [[N]], align 4
+  // CHECK-NEXT: [[T1:%.*]] = zext i32 [[T0]] to i64
+  // CHECK-NEXT: [[T2:%.*]] = mul i64 24, [[T1]]
+  // CHECK-NEXT: [[VLA_SIZE:%.*]] = mul i64 [[T2]], 2
+
+  // Allocate the VLA.
+  // CHECK-NEXT: [[T0:%.*]] = alloca i8, i64 [[VLA_SIZE]], align 16
+  // CHECK-NEXT: [[VLA:%.*]] = bitcast i8* [[T0]] to [3 x i8*]*
+
+  // Zero-initialize.
+  // CHECK-NEXT: [[T0:%.*]] = bitcast [3 x i8*]* [[VLA]] to i8*
+  // CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 [[VLA_SIZE]], i32 8, i1 false)
+
+  // Destroy.
+  // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [3 x i8*]* [[VLA]], i32 0, i32 0
+  // CHECK-NEXT: [[VLA_COUNT:%.*]] = udiv i64 [[VLA_SIZE]], 8
+  // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds i8** [[BEGIN]], i64 [[VLA_COUNT]]
+  // CHECK-NEXT: br label
+
+  // CHECK:      [[CUR:%.*]] = phi i8**
+  // CHECK-NEXT: [[EQ:%.*]] = icmp eq i8** [[CUR]], [[END]]
+  // CHECK-NEXT: br i1 [[EQ]],
+
+  // CHECK:      [[T0:%.*]] = load i8** [[CUR]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
+  // CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds i8** [[CUR]], i32 1
+  // CHECK-NEXT: br label
+
+  // CHECK:      [[T0:%.*]] = load i8** [[SAVED_STACK]]
+  // CHECK-NEXT: call void @llvm.stackrestore(i8* [[T0]])
+  // CHECK-NEXT: ret void
+}
+
+void test22(_Bool cond) {
+  id test22_helper(void) __attribute__((ns_returns_retained));
+
+  // CHECK:      define void @test22(
+  // CHECK:      [[COND:%.*]] = alloca i8,
+  // CHECK-NEXT: [[X:%.*]] = alloca i8*,
+  // CHECK-NEXT: [[RELCOND:%.*]] = alloca i1
+  // CHECK-NEXT: [[RELVAL:%.*]] = alloca i8*
+  // CHECK-NEXT: store i1 false, i1* [[RELCOND]]
+  // CHECK-NEXT: zext
+  // CHECK-NEXT: store
+  // CHECK-NEXT: [[T0:%.*]] = load i8* [[COND]]
+  // CHECK-NEXT: [[T1:%.*]] = trunc i8 [[T0]] to i1
+  // CHECK-NEXT: br i1 [[T1]],
+  // CHECK:      br label
+  // CHECK:      [[CALL:%.*]] = call i8* @test22_helper()
+  // CHECK-NEXT: store i1 true, i1* [[RELCOND]]
+  // CHECK-NEXT: store i8* [[CALL]], i8** [[RELVAL]]
+  // CHECK-NEXT: br label
+  // CHECK:      [[T0:%.*]] = phi i8* [ null, {{%.*}} ], [ [[CALL]], {{%.*}} ]
+  // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) nounwind
+  // CHECK-NEXT: store i8* [[T1]], i8** [[X]],
+  // CHECK-NEXT: [[REL:%.*]] = load i1* [[RELCOND]]
+  // CHECK-NEXT: br i1 [[REL]],
+  // CHECK:      [[T0:%.*]] = load i8** [[RELVAL]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind
+  // CHECK-NEXT: br label
+  // CHECK:      [[T0:%.*]] = load i8** [[X]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind
+  // CHECK-NEXT: ret void
+  id x = (cond ? 0 : test22_helper());
+}
+
+// rdar://problem/8922540
+//   Note that we no longer emit .release_ivars flags.
+// CHECK-GLOBALS: @"\01l_OBJC_CLASS_RO_$_Test23" = internal global [[RO_T:%.*]] { i32 134,
+ at interface Test23 { id x; } @end
+ at implementation Test23 @end
+
+// CHECK-GLOBALS: @"\01l_OBJC_CLASS_RO_$_Test24" = internal global [[RO_T:%.*]] { i32 130,
+ at interface Test24 {} @end
+ at implementation Test24 @end
+
+int (^test25(int x))(void) {
+  // CHECK:    define i32 ()* @test25(
+  // CHECK:      [[X:%.*]] = alloca i32,
+  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:%.*]],
+  // CHECK-NEXT: store i32 {{%.*}}, i32* [[X]]
+  // CHECK:      [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to i32 ()*
+  // CHECK-NEXT: [[T1:%.*]] = bitcast i32 ()* [[T0]] to i8*
+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) nounwind
+  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i32 ()*
+  // CHECK-NEXT: [[T4:%.*]] = bitcast i32 ()* [[T3]] to i8*
+  // CHECK-NEXT: [[T5:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T4]]) nounwind
+  // CHECK-NEXT: [[T6:%.*]] = bitcast i8* [[T5]] to i32 ()*
+  // CHECK-NEXT: ret i32 ()* [[T6]]
+  return ^{ return x; };
+}
+
+// rdar://problem/8941012
+ at interface Test26 { id x[4]; } @end
+ at implementation Test26 @end
+// CHECK:    define internal void @"\01-[Test26 .cxx_destruct]"(
+// CHECK:      [[SELF:%.*]] = load [[TEST26:%.*]]**
+// CHECK-NEXT: [[OFFSET:%.*]] = load i64* @"OBJC_IVAR_$_Test26.x"
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST26]]* [[SELF]] to i8*
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8* [[T0]], i64 [[OFFSET]]
+// CHECK-NEXT: [[X:%.*]] = bitcast i8* [[T1]] to [4 x i8*]*
+// CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [4 x i8*]* [[X]], i32 0, i32 0
+// CHECK-NEXT: [[END:%.*]] = getelementptr inbounds i8** [[BEGIN]], i64 4
+// CHECK-NEXT: br label
+// CHECK:      [[CUR:%.*]] = phi i8**
+// CHECK-NEXT: [[ISDONE:%.*]] = icmp eq i8** [[CUR]], [[END]]
+// CHECK-NEXT: br i1 [[ISDONE]],
+// CHECK:      call void @objc_storeStrong(i8** [[CUR]], i8* null)
+// CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds i8** [[CUR]], i32 1
+// CHECK-NEXT: br label
+// CHECK:      ret void
+
+// Check that 'init' retains self.
+ at interface Test27
+- (id) init;
+ at end
+ at implementation Test27
+- (id) init { return self; }
+// CHECK:    define internal i8* @"\01-[Test27 init]"
+// CHECK:      [[RET:%.*]] = alloca i8*,
+// CHECK-NEXT: [[SELF:%.*]] = alloca [[TEST27:%.*]]*,
+// CHECK-NEXT: [[CMD:%.*]] = alloca i8*,
+// CHECK-NEXT: [[DEST:%.*]] = alloca i32
+// CHECK-NEXT: store [[TEST27]]* {{%.*}}, [[TEST27]]** [[SELF]]
+// CHECK-NEXT: store i8* {{%.*}}, i8** [[CMD]]
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST27]]** [[SELF]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST27]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]]
+// CHECK-NEXT: [[T2:%.*]] = bitcast
+// CHECK-NEXT: store i8* [[T2]], i8** [[RET]]
+// CHECK-NEXT: store i32 {{[0-9]+}}, i32* [[DEST]]
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST27]]** [[SELF]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST27]]* [[T0]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T1]])
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]]
+// CHECK-NEXT: ret i8* [[T0]]
+
+ at end
+
+// rdar://problem/8087194
+ at interface Test28
+ at property (copy) id prop;
+ at end
+ at implementation Test28
+ at synthesize prop;
+ at end
+// CHECK:    define internal void @"\01-[Test28 .cxx_destruct]"
+// CHECK:      [[SELF:%.*]] = load [[TEST28:%.*]]**
+// CHECK-NEXT: [[OFFSET:%.*]] = load i64* @"OBJC_IVAR_$_Test28.prop"
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST28]]* [[SELF]] to i8*
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8* [[T0]], i64 [[OFFSET]]
+// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to i8**
+// CHECK-NEXT: call void @objc_storeStrong(i8** [[T2]], i8* null)
+// CHECK-NEXT: ret void
+
+ at interface Test29_super
+- (id) initWithAllocator: (id) allocator;
+ at end
+ at interface Test29 : Test29_super
+- (id) init;
+- (id) initWithAllocator: (id) allocator;
+ at end
+ at implementation Test29
+static id _test29_allocator = 0;
+- (id) init {
+// CHECK:    define internal i8* @"\01-[Test29 init]"([[TEST29:%.*]]* {{%.*}},
+// CHECK:      [[RET:%.*]] = alloca i8*, align 8
+// CHECK-NEXT: [[SELF:%.*]] = alloca [[TEST29]]*, align 8
+// CHECK-NEXT: [[CMD:%.*]] = alloca i8*, align 8
+// CHECK-NEXT: [[CLEANUP:%.*]] = alloca i32
+// CHECK-NEXT: store [[TEST29]]* {{%.*}}, [[TEST29]]** [[SELF]]
+// CHECK-NEXT: store i8* {{%.*}}, i8** [[CMD]]
+
+// Evaluate arguments.  Note that the send argument is evaluated
+// before the zeroing of self.
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST29]]** [[SELF]], align 8
+// CHECK-NEXT: [[T1:%.*]] = load i8** @_test29_allocator, align 8
+
+// Implicit null of 'self', i.e. direct transfer of ownership.
+// CHECK-NEXT: store [[TEST29]]* null, [[TEST29]]** [[SELF]]
+
+// Actual message send.
+// CHECK-NEXT: [[T2:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[TEST29]]* [[T0]] to i8*
+// CHECK-NEXT: [[CALL:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*, i8*)*)(i8* [[T3]], i8* [[T2]], i8* [[T1]])
+
+// Implicit write of result back into 'self'.  This is not supposed to
+// be detectable because we're supposed to ban accesses to the old
+// self value past the delegate init call.
+// CHECK-NEXT: [[T0:%.*]] = bitcast i8* [[CALL]] to [[TEST29]]*
+// CHECK-NEXT: store [[TEST29]]* [[T0]], [[TEST29]]** [[SELF]]
+
+// Return statement.
+// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[CALL]]
+// CHECK-NEXT: [[CALL:%.*]] = bitcast
+// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[CALL]]) nounwind
+// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast
+// CHECK-NEXT: store i8* [[T1]], i8** [[RET]]
+// CHECK-NEXT: store i32 1, i32* [[CLEANUP]]
+
+// Cleanup.
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST29]]** [[SELF]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST29]]* [[T0]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release
+
+// Return.
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]]
+// CHECK-NEXT: ret i8* [[T0]]
+  return [self initWithAllocator: _test29_allocator];
+}
+- (id) initWithAllocator: (id) allocator {
+// CHECK:    define internal i8* @"\01-[Test29 initWithAllocator:]"(
+// CHECK:      [[RET:%.*]] = alloca i8*, align 8
+// CHECK-NEXT: [[SELF:%.*]] = alloca [[TEST29]]*, align 8
+// CHECK-NEXT: [[CMD:%.*]] = alloca i8*, align 8
+// CHECK-NEXT: [[ALLOCATOR:%.*]] = alloca i8*, align 8
+// CHECK-NEXT: alloca
+// CHECK-NEXT: [[CLEANUP:%.*]] = alloca i32
+// CHECK-NEXT: store [[TEST29]]* {{%.*}}, [[TEST29]]** [[SELF]]
+// CHECK-NEXT: store i8* {{%.*}}, i8** [[CMD]]
+// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* {{%.*}})
+// CHECK-NEXT: store i8* [[T0]], i8** [[ALLOCATOR]]
+
+// Evaluate arguments.  Note that the send argument is evaluated
+// before the zeroing of self.
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST29]]** [[SELF]]
+// CHECK-NEXT: [[T1:%.*]] = load i8** [[ALLOCATOR]], align 8
+
+// Implicit null of 'self', i.e. direct transfer of ownership.
+// CHECK-NEXT: store [[TEST29]]* null, [[TEST29]]** [[SELF]]
+
+// Actual message send.
+// CHECK:      [[CALL:%.*]] = call {{.*}} @objc_msgSendSuper2
+
+// Implicit write of result back into 'self'.  This is not supposed to
+// be detectable because we're supposed to ban accesses to the old
+// self value past the delegate init call.
+// CHECK-NEXT: [[T0:%.*]] = bitcast i8* [[CALL]] to [[TEST29]]*
+// CHECK-NEXT: store [[TEST29]]* [[T0]], [[TEST29]]** [[SELF]]
+
+// Assignment.
+// CHECK-NEXT: [[T0:%.*]] = bitcast i8* [[CALL]] to [[TEST29]]*
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST29]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) nounwind
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST29]]*
+// CHECK-NEXT: [[T4:%.*]] = load [[TEST29]]** [[SELF]], align
+// CHECK-NEXT: store [[TEST29]]* [[T3]], [[TEST29]]** [[SELF]], align
+// CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST29]]* [[T4]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T5]])
+
+// Return statement.
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST29]]** [[SELF]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST29]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) nounwind
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]]
+// CHECK-NEXT: [[T2:%.*]] = bitcast
+// CHECK-NEXT: store i8* [[T2]], i8** [[RET]]
+// CHECK-NEXT: store i32 1, i32* [[CLEANUP]]
+
+// Cleanup.
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[ALLOCATOR]]
+// CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
+
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST29]]** [[SELF]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST29]]* [[T0]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release
+
+// Return.
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]]
+// CHECK-NEXT: ret i8* [[T0]]
+  self = [super initWithAllocator: allocator];
+  return self;
+}
+ at end
+
+typedef struct Test30_helper Test30_helper;
+ at interface Test30
+- (id) init;
+- (Test30_helper*) initHelper;
+ at end
+ at implementation Test30 {
+char *helper;
+}
+- (id) init {
+// CHECK:    define internal i8* @"\01-[Test30 init]"([[TEST30:%.*]]* {{%.*}},
+// CHECK:      [[RET:%.*]] = alloca i8*
+// CHECK-NEXT: [[SELF:%.*]] = alloca [[TEST30]]*
+// CHECK-NEXT: alloca i8*
+// CHECK-NEXT: alloca i32
+// CHECK-NEXT: store [[TEST30]]* {{%.*}}, [[TEST30]]** [[SELF]]
+// CHECK-NEXT: store
+
+// Call.
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST30]]** [[SELF]]
+// CHECK-NEXT: [[T1:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST30]]* [[T0]] to i8*
+// CHECK-NEXT: [[CALL:%.*]] = call [[TEST30_HELPER:%.*]]* bitcast {{.*}} @objc_msgSend {{.*}}(i8* [[T2]], i8* [[T1]])
+
+// Assignment.
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST30_HELPER]]* [[CALL]] to i8*
+// CHECK-NEXT: [[T1:%.*]] = load [[TEST30]]** [[SELF]]
+// CHECK-NEXT: [[IVAR:%.*]] = load i64* @"OBJC_IVAR_$_Test30.helper"
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST30]]* [[T1]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8* [[T2]], i64 [[IVAR]]
+// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to i8**
+// CHECK-NEXT#: [[T5:%.*]] = load i8** [[T4]]
+// CHECK-NEXT#: [[T6:%.*]] = call i8* @objc_retain(i8* [[T0]])
+// CHECK-NEXT#: call void @objc_release(i8* [[T5]])
+// CHECK-NEXT: store i8* [[T0]], i8** [[T4]]
+
+// Return.
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST30]]** [[SELF]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST30]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]]
+// CHECK-NEXT: [[T2:%.*]] = bitcast
+// CHECK-NEXT: store i8* [[T2]], i8** [[RET]]
+// CHECK-NEXT: store i32 1
+
+// Cleanup.
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST30]]** [[SELF]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST30]]* [[T0]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T1]])
+
+// Epilogue.
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[RET]]
+// CHECK-NEXT: ret i8* [[T0]]
+  self->helper = [self initHelper];
+  return self;
+}
+- (Test30_helper*) initHelper {
+// CHECK:    define internal [[TEST30_HELPER]]* @"\01-[Test30 initHelper]"(
+// CHECK:      alloca
+// CHECK-NEXT: alloca
+// CHECK-NEXT: store
+// CHECK-NEXT: store
+// CHECK-NEXT: ret [[TEST30_HELPER]]* null
+  return 0;
+}
+
+ at end
+
+void test31(id x) {
+// CHECK:    define void @test31(
+// CHECK:      [[X:%.*]] = alloca i8*,
+// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:%.*]],
+// CHECK-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{%.*}})
+// CHECK-NEXT: store i8* [[PARM]], i8** [[X]]
+// CHECK:      [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]],
+// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
+// CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]],
+// CHECK-NEXT: bitcast
+// CHECK-NEXT: call void @test31_helper(
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]]
+// CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]]
+// CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
+// CHECK-NEXT: ret void
+  extern void test31_helper(id (^)(void));
+  test31_helper(^{ return x; });
+}
+
+__attribute__((ns_returns_retained)) id test32(void) {
+// CHECK:    define i8* @test32()
+// CHECK:      [[CALL:%.*]] = call i8* @test32_helper()
+// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[CALL]])
+// CHECK-NEXT: ret i8* [[T0]]
+  extern id test32_helper(void);
+  return test32_helper();
+}
+
+ at class Test33_a;
+ at interface Test33
+- (void) give: (Test33_a **) x;
+- (void) take: (Test33_a **) x;
+- (void) giveStrong: (out __strong Test33_a **) x;
+- (void) takeStrong: (inout __strong Test33_a **) x;
+- (void) giveOut: (out Test33_a **) x;
+ at end
+void test33(Test33 *ptr) {
+  Test33_a *a;
+  [ptr give: &a];
+  [ptr take: &a];
+  [ptr giveStrong: &a];
+  [ptr takeStrong: &a];
+  [ptr giveOut: &a];
+
+  // CHECK:    define void @test33([[TEST33:%.*]]*
+  // CHECK:      [[PTR:%.*]] = alloca [[TEST33]]*
+  // CHECK-NEXT: [[A:%.*]] = alloca [[A_T:%.*]]*
+  // CHECK-NEXT: [[TEMP0:%.*]] = alloca [[A_T]]*
+  // CHECK-NEXT: [[TEMP1:%.*]] = alloca [[A_T]]*
+  // CHECK-NEXT: [[TEMP2:%.*]] = alloca [[A_T]]*
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: objc_retain
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: store
+  // CHECK-NEXT: store [[A_T]]* null, [[A_T]]** [[A]]
+
+  // CHECK-NEXT: load [[TEST33]]** [[PTR]]
+  // CHECK-NEXT: [[T0:%.*]] = load [[A_T]]** [[A]]
+  // CHECK-NEXT: store [[A_T]]* [[T0]], [[A_T]]** [[TEMP0]]
+  // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: objc_msgSend{{.*}}, [[A_T]]** [[TEMP0]])
+  // CHECK-NEXT: [[T0:%.*]] = load [[A_T]]** [[TEMP0]]
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[A_T]]* [[T0]] to i8*
+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
+  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A_T]]*
+  // CHECK-NEXT: [[T4:%.*]] = load [[A_T]]** [[A]]
+  // CHECK-NEXT: store [[A_T]]* [[T3]], [[A_T]]** [[A]]
+  // CHECK-NEXT: [[T5:%.*]] = bitcast [[A_T]]* [[T4]] to i8*
+  // CHECK-NEXT: call void @objc_release(i8* [[T5]])
+
+  // CHECK-NEXT: load [[TEST33]]** [[PTR]]
+  // CHECK-NEXT: [[T0:%.*]] = load [[A_T]]** [[A]]
+  // CHECK-NEXT: store [[A_T]]* [[T0]], [[A_T]]** [[TEMP1]]
+  // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: objc_msgSend{{.*}}, [[A_T]]** [[TEMP1]])
+  // CHECK-NEXT: [[T0:%.*]] = load [[A_T]]** [[TEMP1]]
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[A_T]]* [[T0]] to i8*
+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
+  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A_T]]*
+  // CHECK-NEXT: [[T4:%.*]] = load [[A_T]]** [[A]]
+  // CHECK-NEXT: store [[A_T]]* [[T3]], [[A_T]]** [[A]]
+  // CHECK-NEXT: [[T5:%.*]] = bitcast [[A_T]]* [[T4]] to i8*
+  // CHECK-NEXT: call void @objc_release(i8* [[T5]])
+
+  // CHECK-NEXT: load [[TEST33]]** [[PTR]]
+  // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: objc_msgSend{{.*}}, [[A_T]]** [[A]])
+
+  // CHECK-NEXT: load [[TEST33]]** [[PTR]]
+  // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: objc_msgSend{{.*}}, [[A_T]]** [[A]])
+
+  // 'out'
+  // CHECK-NEXT: load [[TEST33]]** [[PTR]]
+  // CHECK-NEXT: store [[A_T]]* null, [[A_T]]** [[TEMP2]]
+  // CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: objc_msgSend{{.*}}, [[A_T]]** [[TEMP2]])
+  // CHECK-NEXT: [[T0:%.*]] = load [[A_T]]** [[TEMP2]]
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[A_T]]* [[T0]] to i8*
+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
+  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A_T]]*
+  // CHECK-NEXT: [[T4:%.*]] = load [[A_T]]** [[A]]
+  // CHECK-NEXT: store [[A_T]]* [[T3]], [[A_T]]** [[A]]
+  // CHECK-NEXT: [[T5:%.*]] = bitcast [[A_T]]* [[T4]] to i8*
+  // CHECK-NEXT: call void @objc_release(i8* [[T5]])
+
+  // CHECK-NEXT: load
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: objc_release
+  // CHECK-NEXT: load
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: objc_release
+  // CHECK-NEXT: ret void
+}
+
+void test34(int cond) {
+  __strong id strong;
+  __weak id weak;
+  extern void test34_sink(id *);
+  test34_sink(cond ? &strong : 0);
+  test34_sink(cond ? &weak : 0);
+
+  // CHECK:    define void @test34(
+  // CHECK:      [[COND:%.*]] = alloca i32
+  // CHECK-NEXT: [[STRONG:%.*]] = alloca i8*
+  // CHECK-NEXT: [[WEAK:%.*]] = alloca i8*
+  // CHECK-NEXT: [[TEMP1:%.*]] = alloca i8*
+  // CHECK-NEXT: [[TEMP2:%.*]] = alloca i8*
+  // CHECK-NEXT: store i32
+  // CHECK-NEXT: store i8* null, i8** [[STRONG]]
+  // CHECK-NEXT: call i8* @objc_initWeak(i8** [[WEAK]], i8* null)
+
+  // CHECK-NEXT: [[T0:%.*]] = load i32* [[COND]]
+  // CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], 0
+  // CHECK:      [[ARG:%.*]] = phi i8**
+  // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
+  // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i8** null, i8** [[TEMP1]]
+  // CHECK-NEXT: br i1 [[T0]],
+  // CHECK:      [[T0:%.*]] = load i8** [[ARG]]
+  // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP1]]
+  // CHECK-NEXT: br label
+  // CHECK:      call void @test34_sink(i8** [[T1]])
+  // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
+  // CHECK-NEXT: br i1 [[T0]],
+  // CHECK:      [[T0:%.*]] = load i8** [[TEMP1]]
+  // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
+  // CHECK-NEXT: [[T2:%.*]] = load i8** [[ARG]]
+  // CHECK-NEXT: store i8* [[T1]], i8** [[ARG]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T2]])
+  // CHECK-NEXT: br label
+
+  // CHECK:      [[T0:%.*]] = load i32* [[COND]]
+  // CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], 0
+  // CHECK:      [[ARG:%.*]] = phi i8**
+  // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
+  // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i8** null, i8** [[TEMP2]]
+  // CHECK-NEXT: br i1 [[T0]],
+  // CHECK:      [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[ARG]])
+  // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP2]]
+  // CHECK-NEXT: br label
+  // CHECK:      call void @test34_sink(i8** [[T1]])
+  // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
+  // CHECK-NEXT: br i1 [[T0]],
+  // CHECK:      [[T0:%.*]] = load i8** [[TEMP2]]
+  // CHECK-NEXT: call i8* @objc_storeWeak(i8** [[ARG]], i8* [[T0]])
+  // CHECK-NEXT: br label
+
+  // CHECK:      call void @objc_destroyWeak(i8** [[WEAK]])
+  // CHECK:      ret void
+}
+
+void test35(void (^sink)(id*)) {
+  __strong id strong;
+  sink(&strong);
+
+  // CHECK:    define void @test35(
+  // CHECK:      [[SINK:%.*]] = alloca void (i8**)*
+  // CHECK-NEXT: [[STRONG:%.*]] = alloca i8*
+  // CHECK-NEXT: [[TEMP:%.*]] = alloca i8*
+  // CHECK-NEXT: bitcast void (i8**)* {{%.*}} to i8*
+  // CHECK-NEXT: call i8* @objc_retain(
+  // CHECK-NEXT: bitcast i8*
+  // CHECK-NEXT: store void (i8**)* {{%.*}}, void (i8**)** [[SINK]]
+  // CHECK-NEXT: store i8* null, i8** [[STRONG]]
+
+  // CHECK-NEXT: load void (i8**)** [[SINK]]
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: getelementptr
+  // CHECK-NEXT: [[BLOCK:%.*]] = bitcast
+  // CHECK-NEXT: [[T0:%.*]] = load i8** [[STRONG]]
+  // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP1]]
+  // CHECK-NEXT: [[F0:%.*]] = load i8**
+  // CHECK-NEXT: [[F1:%.*]] = bitcast i8* [[F0]] to void (i8*, i8**)*
+  // CHECK-NEXT: call void [[F1]](i8* [[BLOCK]], i8** [[TEMP1]])
+  // CHECK-NEXT: [[T0:%.*]] = load i8** [[TEMP1]]
+  // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
+  // CHECK-NEXT: [[T2:%.*]] = load i8** [[STRONG]]
+  // CHECK-NEXT: store i8* [[T1]], i8** [[STRONG]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T2]])
+
+  // CHECK-NEXT: [[T0:%.*]] = load i8** [[STRONG]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+
+  // CHECK-NEXT: load void (i8**)** [[SINK]]
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: call void @objc_release
+  // CHECK-NEXT: ret void
+
+}
+
+// CHECK: define void @test36
+void test36(id x) {
+  // CHECK: [[X:%.*]] = alloca i8*
+
+  // CHECK: call i8* @objc_retain
+  // CHECK: call i8* @objc_retain
+  // CHECK: call i8* @objc_retain
+  id array[3] = { @"A", x, @"y" };
+
+  // CHECK:      [[T0:%.*]] = load i8** [[X]]
+  // CHECK-NEXT: store i8* null, i8** [[X]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+  x = 0;
+
+  // CHECK: br label
+  // CHECK: call void @objc_release
+  // CHECK: br label
+
+  // CHECK: call void @objc_release
+  // CHECK-NEXT: ret void
+}
+
+ at class Test37;
+void test37(void) {
+  extern void test37_helper(id *);
+  Test37 *var;
+  test37_helper(&var);
+
+  // CHECK:    define void @test37()
+  // CHECK:      [[VAR:%.*]] = alloca [[TEST37:%.*]]*,
+  // CHECK-NEXT: [[TEMP:%.*]] = alloca i8*
+  // CHECK-NEXT: store [[TEST37]]* null, [[TEST37]]** [[VAR]]
+
+  // CHECK-NEXT: [[T0:%.*]] = load [[TEST37]]** [[VAR]]
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST37]]* [[T0]] to i8*
+  // CHECK-NEXT: store i8* [[T1]], i8** [[TEMP]]
+  // CHECK-NEXT: call void @test37_helper(i8** [[TEMP]])
+  // CHECK-NEXT: [[T0:%.*]] = load i8** [[TEMP]]
+  // CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[TEST37]]*
+  // CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST37]]* [[T1]] to i8*
+  // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]])
+  // CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[TEST37]]*
+  // CHECK-NEXT: [[T5:%.*]] = load [[TEST37]]** [[VAR]]
+  // CHECK-NEXT: store [[TEST37]]* [[T4]], [[TEST37]]** [[VAR]]
+  // CHECK-NEXT: [[T6:%.*]] = bitcast [[TEST37]]* [[T5]] to i8*
+  // CHECK-NEXT: call void @objc_release(i8* [[T6]])
+
+  // CHECK-NEXT: [[T0:%.*]] = load [[TEST37]]** [[VAR]]
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST37]]* [[T0]] to i8*
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+  // CHECK-NEXT: ret void
+}
+
+void test38(void) {
+  id test38_source(void);
+  void test38_helper(void (^)(void));
+  __block id var = test38_source();
+  test38_helper(^{ var = 0; });
+
+  // CHECK:    define void @test38()
+  // CHECK:      [[VAR:%.*]] = alloca [[BYREF_T:%.*]],
+  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:%.*]],
+  // CHECK:      [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 2
+  // 0x02000000 - has copy/dispose helpers
+  // CHECK-NEXT: store i32 33554432, i32* [[T0]]
+  // CHECK:      [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
+  // CHECK-NEXT: [[T0:%.*]] = call i8* @test38_source()
+  // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+  // CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]]
+  // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
+  // 0x42000000 - has signature, copy/dispose helpers
+  // CHECK:      store i32 1107296256,
+  // CHECK:      [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
+  // CHECK-NEXT: store i8* [[T0]], i8**
+  // CHECK:      call void @test38_helper(
+  // CHECK:      [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
+  // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
+  // CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+  // CHECK-NEXT: ret void
+
+  // CHECK:    define internal void @__Block_byref_object_copy_
+  // CHECK:      [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
+  // CHECK-NEXT: load i8**
+  // CHECK-NEXT: bitcast i8* {{%.*}} to [[BYREF_T]]*
+  // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
+  // CHECK-NEXT: [[T2:%.*]] = load i8** [[T1]]
+  // CHECK-NEXT: store i8* [[T2]], i8** [[T0]]
+  // CHECK-NEXT: store i8* null, i8** [[T1]]
+
+  // CHECK:    define internal void @__Block_byref_object_dispose_
+  // CHECK:      [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
+  // CHECK-NEXT: [[T1:%.*]] = load i8** [[T0]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+
+  // CHECK:    define internal void @__test38_block_invoke_
+  // CHECK:      [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
+  // CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]], align 8
+  // CHECK-NEXT: store i8* null, i8** [[SLOT]],
+  // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+  // CHECK-NEXT: ret void
+
+  // CHECK:    define internal void @__copy_helper_block_
+  // CHECK:      call void @_Block_object_assign(i8* {{%.*}}, i8* {{%.*}}, i32 8)
+
+  // CHECK:    define internal void @__destroy_helper_block_
+  // CHECK:      call void @_Block_object_dispose(i8* {{%.*}}, i32 8)
+}
+
+void test39(void) {
+  extern id test39_source(void);
+  void test39_helper(void (^)(void));
+  __unsafe_unretained id var = test39_source();
+  test39_helper(^{ (void) var; });
+
+  // CHECK:    define void @test39()
+  // CHECK:      [[VAR:%.*]] = alloca i8*
+  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:%.*]],
+  // CHECK-NEXT: [[T0:%.*]] = call i8* @test39_source()
+  // CHECK-NEXT: store i8* [[T0]], i8** [[VAR]],
+  // 0x40000000 - has signature but no copy/dispose
+  // CHECK:      store i32 1073741824, i32*
+  // CHECK:      [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+  // CHECK-NEXT: [[T0:%.*]] = load i8** [[VAR]]
+  // CHECK-NEXT: store i8* [[T0]], i8** [[CAPTURE]]
+  // CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
+  // CHECK-NEXT: call void @test39_helper(void ()* [[T0]])
+  // CHECK-NEXT: ret void
+}
+
+void test40(void) {
+  id test40_source(void);
+  void test40_helper(void (^)(void));
+  __block __weak id var = test40_source();
+  test40_helper(^{ var = 0; });
+
+  // CHECK:    define void @test40()
+  // CHECK:      [[VAR:%.*]] = alloca [[BYREF_T:%.*]],
+  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:%.*]],
+  // CHECK:      [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 2
+  // 0x02000000 - has copy/dispose helpers
+  // CHECK-NEXT: store i32 33554432, i32* [[T0]]
+  // CHECK:      [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
+  // CHECK-NEXT: [[T0:%.*]] = call i8* @test40_source()
+  // CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T0]])
+  // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
+  // 0x42000000 - has signature, copy/dispose helpers
+  // CHECK:      store i32 1107296256,
+  // CHECK:      [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
+  // CHECK-NEXT: store i8* [[T0]], i8**
+  // CHECK:      call void @test40_helper(
+  // CHECK:      [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
+  // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
+  // CHECK-NEXT: call void @objc_destroyWeak(i8** [[SLOT]])
+  // CHECK-NEXT: ret void
+
+  // CHECK:    define internal void @__Block_byref_object_copy_
+  // CHECK:      [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
+  // CHECK-NEXT: load i8**
+  // CHECK-NEXT: bitcast i8* {{%.*}} to [[BYREF_T]]*
+  // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
+  // CHECK-NEXT: call void @objc_moveWeak(i8** [[T0]], i8** [[T1]])
+
+  // CHECK:    define internal void @__Block_byref_object_dispose_
+  // CHECK:      [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
+  // CHECK-NEXT: call void @objc_destroyWeak(i8** [[T0]])
+
+  // CHECK:    define internal void @__test40_block_invoke_
+  // CHECK:      [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
+  // CHECK-NEXT: call i8* @objc_storeWeak(i8** [[SLOT]], i8* null)
+  // CHECK-NEXT: ret void
+
+  // CHECK:    define internal void @__copy_helper_block_
+  // 0x8 - FIELD_IS_BYREF (no FIELD_IS_WEAK because clang in control)
+  // CHECK:      call void @_Block_object_assign(i8* {{%.*}}, i8* {{%.*}}, i32 8)
+
+  // CHECK:    define internal void @__destroy_helper_block_
+  // 0x8 - FIELD_IS_BYREF (no FIELD_IS_WEAK because clang in control)
+  // CHECK:      call void @_Block_object_dispose(i8* {{%.*}}, i32 8)
+}
+
+void test41(void) {
+  id test41_source(void);
+  void test41_helper(void (^)(void));
+  void test41_consume(id);
+  __weak id var = test41_source();
+  test41_helper(^{ test41_consume(var); });
+
+  // CHECK:    define void @test41()
+  // CHECK:      [[VAR:%.*]] = alloca i8*,
+  // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:%.*]],
+  // CHECK:      [[T0:%.*]] = call i8* @test41_source()
+  // CHECK-NEXT: call i8* @objc_initWeak(i8** [[VAR]], i8* [[T0]])
+  // 0x42000000 - has signature, copy/dispose helpers
+  // CHECK:      store i32 1107296256,
+  // CHECK:      [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+  // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[VAR]])
+  // CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T0]])
+  // CHECK:      call void @test41_helper(
+  // CHECK-NEXT: call void @objc_destroyWeak(i8** [[SLOT]])
+  // CHECK-NEXT: call void @objc_destroyWeak(i8** [[VAR]])
+  // CHECK-NEXT: ret void
+
+  // CHECK:    define internal void @__test41_block_invoke_
+  // CHECK:      [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* {{%.*}}, i32 0, i32 5
+  // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[SLOT]])
+  // CHECK-NEXT: call void @test41_consume(i8* [[T0]])
+  // CHECK-NEXT: ret void
+
+  // CHECK:    define internal void @__copy_helper_block_
+  // CHECK:      getelementptr
+  // CHECK-NEXT: getelementptr
+  // CHECK-NEXT: call void @objc_copyWeak(
+
+  // CHECK:    define internal void @__destroy_helper_block_
+  // CHECK:      getelementptr
+  // CHECK-NEXT: call void @objc_destroyWeak(
+}
+
+ at interface Test42 @end
+ at implementation Test42
+- (void) test {
+// CHECK:    define internal void @"\01-[Test42 test]"
+// CHECK:      [[SELF:%.*]] = alloca [[TEST42:%.*]]*,
+// CHECK-NEXT: alloca i8*
+// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:%.*]],
+// CHECK-NEXT: store
+// CHECK-NEXT: store
+// CHECK:      [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+// CHECK-NEXT: [[T1:%.*]] = load [[TEST42]]** [[SELF]],
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST42]]* [[T1]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]])
+// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[TEST42]]*
+// CHECK-NEXT: store [[TEST42]]* [[T4]], [[TEST42]]** [[T0]]
+// CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
+// CHECK-NEXT: call void @test42_helper(
+// CHECK-NEXT: [[T1:%.*]] = load [[TEST42]]** [[T0]]
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST42]]* [[T1]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T2]])
+// CHECK-NEXT: ret void
+
+  extern void test42_helper(void (^)(void));
+  test42_helper(^{ (void) self; });
+}
+ at end
+
+ at interface Test43 @end
+ at implementation Test43
+- (id) test __attribute__((ns_returns_retained)) {
+  extern id test43_produce(void);
+  return test43_produce();
+  // CHECK:      call i8* @test43_produce()
+  // CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue(
+  // CHECK-NEXT: ret 
+}
+ at end
+
+id test44(void) {
+  typedef id __attribute__((ns_returns_retained)) blocktype(void);
+  extern test44_consume_block(blocktype^);
+  return ^blocktype {
+      extern id test44_produce(void);
+      return test44_produce();
+  }();
+
+// CHECK:    define i8* @test44(
+// CHECK:      load i8** getelementptr
+// CHECK-NEXT: bitcast i8*
+// CHECK-NEXT: call i8* 
+// CHECK-NEXT: call i8* @objc_autoreleaseReturnValue
+// CHECK-NEXT: ret i8*
+
+// CHECK:      call i8* @test44_produce()
+// CHECK-NEXT: call i8* @objc_retain
+// CHECK-NEXT: ret i8*
+}
+
+ at interface Test45
+ at property (retain) id x;
+ at end
+ at implementation Test45
+ at synthesize x;
+ at end
+// CHECK:    define internal i8* @"\01-[Test45 x]"(
+// CHECK:      [[CALL:%.*]] = call i8* @objc_getProperty(
+// CHECK-NEXT: ret i8* [[CALL]]
+
+// rdar://problem/9315552
+void test46(__weak id *wp, __weak volatile id *wvp) {
+  extern id test46_helper(void);
+
+  // TODO: this is sub-optimal, we should retain at the actual call site.
+
+  // CHECK:      [[T0:%.*]] = call i8* @test46_helper()
+  // CHECK-NEXT: [[T1:%.*]] = load i8*** {{%.*}}, align 8
+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_storeWeak(i8** [[T1]], i8* [[T0]])
+  // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]])
+  // CHECK-NEXT: store i8* [[T3]], i8**
+  id x = *wp = test46_helper();
+
+  // CHECK:      [[T0:%.*]] = call i8* @test46_helper()
+  // CHECK-NEXT: [[T1:%.*]] = load i8*** {{%.*}}, align 8
+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_storeWeak(i8** [[T1]], i8* [[T0]])
+  // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]])
+  // CHECK-NEXT: store i8* [[T3]], i8**
+  id y = *wvp = test46_helper();
+}
+
+// rdar://problem/9378887
+void test47(void) {
+  extern id test47_helper(void);
+  id x = x = test47_helper();
+
+  // CHECK:    define void @test47()
+  // CHECK:      [[X:%.*]] = alloca i8*
+  // CHECK-NEXT: store i8* null, i8** [[X]]
+  // CHECK-NEXT: [[CALL:%.*]] = call i8* @test47_helper()
+  // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[CALL]])
+  // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
+  // CHECK-NEXT: store i8* [[T0]], i8** [[X]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]])
+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T0]])
+  // CHECK-NEXT: [[T3:%.*]] = load i8** [[X]]
+  // CHECK-NEXT: store i8* [[T2]], i8** [[X]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T3]])
+  // CHECK-NEXT: [[T4:%.*]] = load i8** [[X]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T4]])
+  // CHECK-NEXT: ret void
+}
+
+void test48(void) {
+  extern id test48_helper(void);
+  __weak id x = x = test48_helper();
+  // CHECK:    define void @test48()
+  // CHECK:      [[X:%.*]] = alloca i8*
+  // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_initWeak(i8** [[X]], i8* null)
+  // CHECK-NEXT: [[T1:%.*]] = call i8* @test48_helper()
+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_storeWeak(i8** [[X]], i8* [[T1]])
+  // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_storeWeak(i8** [[X]], i8* [[T2]])
+  // CHECK-NEXT: call void @objc_destroyWeak(i8** [[X]])
+  // CHECK-NEXT: ret void
+}
+
+void test49(void) {
+  extern id test49_helper(void);
+  __autoreleasing id x = x = test49_helper();
+  // CHECK:    define void @test49()
+  // CHECK:      [[X:%.*]] = alloca i8*
+  // CHECK-NEXT: store i8* null, i8** [[X]]
+  // CHECK-NEXT: [[CALL:%.*]] = call i8* @test49_helper()
+  // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[CALL]])
+  // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_autorelease(i8* [[T0]])
+  // CHECK-NEXT: store i8* [[T2]], i8** [[X]]
+  // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]])
+  // CHECK-NEXT: store i8* [[T3]], i8** [[X]]
+  // CHECK-NEXT: ret void
+}
+
+// rdar://9380136
+id x();
+void test50(id y) {
+  ({x();});
+// CHECK: [[T0:%.*]] = call i8* @objc_retain
+// CHECK: call void @objc_release
+}
+
+
+// rdar://9400762
+struct CGPoint {
+  float x;
+  float y;
+};
+typedef struct CGPoint CGPoint;
+
+ at interface Foo
+ at property (assign) CGPoint point;
+ at end
+
+ at implementation Foo
+ at synthesize point;
+ at end
+
+// rdar://problem/9400398
+id test52(void) {
+  id test52_helper(int) __attribute__((ns_returns_retained));
+  return ({ int x = 5; test52_helper(x); });
+
+// CHECK:    define i8* @test52()
+// CHECK:      [[X:%.*]] = alloca i32
+// CHECK-NEXT: store i32 5, i32* [[X]],
+// CHECK-NEXT: [[T0:%.*]] = load i32* [[X]],
+// CHECK-NEXT: [[T1:%.*]] = call i8* @test52_helper(i32 [[T0]])
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T1]])
+// CHECK-NEXT: ret i8* [[T2]]
+}
+
+// rdar://problem/9400644
+void test53(void) {
+  id test53_helper(void);
+  id x = ({ id y = test53_helper(); y; });
+  (void) x;
+// CHECK:    define void @test53()
+// CHECK:      [[X:%.*]] = alloca i8*,
+// CHECK-NEXT: [[Y:%.*]] = alloca i8*,
+// CHECK-NEXT: [[T0:%.*]] = call i8* @test53_helper()
+// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+// CHECK-NEXT: store i8* [[T1]], i8** [[Y]],
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[Y]],
+// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
+// CHECK-NEXT: [[T2:%.*]] = load i8** [[Y]]
+// CHECK-NEXT: call void @objc_release(i8* [[T2]])
+// CHECK-NEXT: store i8* [[T1]], i8** [[X]],
+// CHECK-NEXT: load i8** [[X]],
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]]
+// CHECK-NEXT: call void @objc_release(i8* [[T0]])
+// CHECK-NEXT: ret void
+}

Added: cfe/trunk/test/CodeGenObjC/autorelease.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/autorelease.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/autorelease.m (added)
+++ cfe/trunk/test/CodeGenObjC/autorelease.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fobjc-nonfragile-abi -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -emit-llvm -fobjc-nonfragile-abi -o - %s | FileCheck %s
+// rdar://8881826
+// rdar://9412038
+
+ at interface I
+{
+  id ivar;
+}
+- (id) Meth;
++ (id) MyAlloc;;
+ at end
+
+ at implementation I
+- (id) Meth {
+   @autoreleasepool {
+      id p = [I MyAlloc];
+      if (!p)
+        return ivar;
+   }
+  return 0;
+}
++ (id) MyAlloc {
+    return 0;
+}
+ at end
+
+// CHECK: call i8* @objc_autoreleasePoolPush
+// CHECK: [[T:%.*]] = load i8** [[A:%.*]]
+// CHECK: call void @objc_autoreleasePoolPop

Modified: cfe/trunk/test/CodeGenObjC/block-6.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/block-6.m?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjC/block-6.m (original)
+++ cfe/trunk/test/CodeGenObjC/block-6.m Wed Jun 15 18:02:42 2011
@@ -2,10 +2,16 @@
 // rdar://8893785
 
 void MYFUNC() {
-// CHECK: [[T1:%.*]] = bitcast i8* ()*
-// CHECK-NEXT: [[FORWARDING:%.*]] = getelementptr inbounds [[N_T:%.*]]* [[N:%.*]], i32 0, i32 1
-// CHECK-NEXT: [[T0:%.*]] = load [[N_T]]** [[FORWARDING]]
-// CHECK-NEXT: [[OBSERVER:%.*]] = getelementptr inbounds [[N_T]]* [[T0]], i32 0, i32 6
+// CHECK:    define void @MYFUNC()
+// CHECK:      [[OBSERVER_SLOT:%.*]] = alloca [[OBSERVER_T:%.*]], align 8
+
+// CHECK:      [[T0:%.*]] = getelementptr inbounds [[OBSERVER_T]]* [[OBSERVER_SLOT]], i32 0, i32 1
+// CHECK:      store [[OBSERVER_T]]* [[OBSERVER_SLOT]], [[OBSERVER_T]]** [[T0]]
+
+// CHECK:      [[T1:%.*]] = bitcast i8* ()*
+// CHECK:      [[FORWARDING:%.*]] = getelementptr inbounds [[OBSERVER_T]]* [[OBSERVER_SLOT]], i32 0, i32 1
+// CHECK-NEXT: [[T0:%.*]] = load [[OBSERVER_T]]** [[FORWARDING]]
+// CHECK-NEXT: [[OBSERVER:%.*]] = getelementptr inbounds [[OBSERVER_T]]* [[T0]], i32 0, i32 6
 // CHECK-NEXT: store i8* [[T1]], i8** [[OBSERVER]]
   __block id observer = ^{ return observer; };
 }

Added: cfe/trunk/test/CodeGenObjC/mrr-autorelease.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/mrr-autorelease.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/mrr-autorelease.m (added)
+++ cfe/trunk/test/CodeGenObjC/mrr-autorelease.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// rdar://8881826
+// rdar://9423507
+
+ at interface I
+{
+  id ivar;
+}
+- (id) Meth;
+ at end
+
+ at implementation I
+- (id) Meth {
+   @autoreleasepool {
+   }
+  return 0;
+}
+ at end
+
+// CHECK-NOT: call i8* @objc_getClass
+// CHECK: call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+// CHECK: call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend

Added: cfe/trunk/test/CodeGenObjC/nonlazy-msgSend.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/nonlazy-msgSend.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/nonlazy-msgSend.m (added)
+++ cfe/trunk/test/CodeGenObjC/nonlazy-msgSend.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -emit-llvm -o %t %s
+// RUN: grep -F 'declare i8* @objc_msgSend(i8*, i8*, ...) nonlazybind' %t
+
+void f0(id x) {
+  [x foo];
+}

Added: cfe/trunk/test/CodeGenObjC/related-result-type.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/related-result-type.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/related-result-type.m (added)
+++ cfe/trunk/test/CodeGenObjC/related-result-type.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+
+ at interface NSObject
++ (id)alloc;
+- (id)init;
+- (id)retain;
+ at end
+
+ at interface NSString : NSObject
+ at end
+
+// CHECK: define void @test1()
+void test1() {
+  // CHECK: {{call.*@objc_msgSend}}
+  // CHECK: {{call.*@objc_msgSend}}
+  // CHECK: {{call.*@objc_msgSend}}
+  // CHECK: bitcast i8*
+  NSString *str1 = [[[NSString alloc] init] retain];
+}
+
+// CHECK: define void @test2()
+void test2() {
+  // CHECK: {{call.*@objc_msgSend}}
+  // CHECK: {{call.*@objc_msgSend}}
+  // CHECK: {{call.*@objc_msgSend}}
+  // CHECK: bitcast i8*
+  NSString *str1 = NSString.alloc.init.retain;
+}
+
+ at interface Test2 : NSString
+- (id)init;
+ at end
+
+ at implementation Test2
+// CHECK: define internal i8* @"\01-[Test2 init]"
+- (id)init {
+  // CHECK: {{call.*@objc_msgSendSuper}}
+  // CHECK-NEXT: bitcast i8*
+  return [super init];
+}
+ at end
+
+ at interface Test3 : NSString
+- (id)init;
+ at end
+
+ at implementation Test3
+// CHECK: define internal i8* @"\01-[Test3 init]"
+- (id)init {
+  // CHECK: {{call.*@objc_msgSendSuper}}
+  // CHECK-NEXT: bitcast i8*
+  return [super init];
+}
+ at end

Added: cfe/trunk/test/CodeGenObjCXX/arc-globals.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/arc-globals.mm?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/arc-globals.mm (added)
+++ cfe/trunk/test/CodeGenObjCXX/arc-globals.mm Wed Jun 15 18:02:42 2011
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fblocks -fobjc-arc -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+
+// Test that we're properly retaining lifetime-qualified pointers
+// initialized statically and wrapping up those initialization in an
+// autorelease pool.
+id getObject();
+
+// CHECK: define internal void @__cxx_global_var_init
+// CHECK: call i8* @_Z9getObjectv
+// CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue
+// CHECK-NEXT: {{store i8*.*@global_obj}}
+// CHECK-NEXT: ret void
+id global_obj = getObject();
+
+// CHECK: define internal void @__cxx_global_var_init
+// CHECK: call i8* @_Z9getObjectv
+// CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue
+// CHECK-NEXT: {{store i8*.*@global_obj2}}
+// CHECK-NEXT: ret void
+id global_obj2 = getObject();
+
+// CHECK: define internal void @_GLOBAL__I_a
+// CHECK: call i8* @objc_autoreleasePoolPush()
+// CHECK-NEXT: call void @__cxx_global_var_init
+// CHECK-NEXT: call void @__cxx_global_var_init1
+// CHECK-NEXT: call void @objc_autoreleasePoolPop(
+// CHECK-NEXT: ret void

Added: cfe/trunk/test/CodeGenObjCXX/arc-mangle.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/arc-mangle.mm?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/arc-mangle.mm (added)
+++ cfe/trunk/test/CodeGenObjCXX/arc-mangle.mm Wed Jun 15 18:02:42 2011
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-arc -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: define void @_Z1fPU8__strongP11objc_object(i8**)
+void f(__strong id *) {}
+// CHECK: define void @_Z1fPU6__weakP11objc_object(i8**)
+void f(__weak id *) {}
+// CHECK: define void @_Z1fPU15__autoreleasingP11objc_object(i8**)
+void f(__autoreleasing id *) {}
+// CHECK: define void @_Z1fPU19__unsafe_unretainedP11objc_object(i8**)
+void f(__unsafe_unretained id *) {}
+// CHECK: define void @_Z1fPKU8__strongP11objc_object(i8**)
+void f(const __strong id *) {}
+// CHECK: define void @_Z1fPKU6__weakP11objc_object(i8**)
+void f(const __weak id *) {}
+// CHECK: define void @_Z1fPKU15__autoreleasingP11objc_object(i8**)
+void f(const __autoreleasing id *) {}
+// CHECK: define void @_Z1fPKU19__unsafe_unretainedP11objc_object(i8**)
+void f(const __unsafe_unretained id *) {}
+
+
+template<unsigned N> struct unsigned_c { };
+
+// CHECK: define weak_odr void @_Z1gIKvEvP10unsigned_cIXplszv1U8__bridgecvPT_v1U8__bridgecvP11objc_objectcvS3_Li0ELi1EEE
+template<typename T>void g(unsigned_c<sizeof((__bridge T*)(__bridge id)(T*)0) + 1>*) {}
+template void g<const void>(unsigned_c<sizeof(id) + 1> *);

Added: cfe/trunk/test/CodeGenObjCXX/arc-new-delete.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/arc-new-delete.mm?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/arc-new-delete.mm (added)
+++ cfe/trunk/test/CodeGenObjCXX/arc-new-delete.mm Wed Jun 15 18:02:42 2011
@@ -0,0 +1,86 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-arc -fblocks -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s | FileCheck %s
+
+typedef __strong id strong_id;
+typedef __weak id weak_id;
+
+// CHECK: define void @_Z8test_newP11objc_object
+void test_new(id invalue) {
+  // CHECK: alloca i8*
+  // CHECK-NEXT: call i8* @objc_retain
+
+  // CHECK: call noalias i8* @_Znwm
+  // CHECK-NEXT: {{bitcast i8\*.*to i8\*\*}}
+  // CHECK-NEXT: store i8* null, i8**
+  new strong_id;
+  // CHECK: call noalias i8* @_Znwm
+  // CHECK-NEXT: {{bitcast i8\*.*to i8\*\*}}
+  // CHECK-NEXT: store i8* null, i8**
+  new weak_id;
+
+  // CHECK: call noalias i8* @_Znwm
+  // CHECK-NEXT: {{bitcast i8\*.*to i8\*\*}}
+  // CHECK-NEXT: store i8* null, i8**
+  new __strong id;
+  // CHECK: call noalias i8* @_Znwm
+  // CHECK-NEXT: {{bitcast i8\*.*to i8\*\*}}
+  // CHECK-NEXT: store i8* null, i8**
+  new __weak id;
+
+  // CHECK: call noalias i8* @_Znwm
+  // CHECK: call i8* @objc_retain
+  // CHECK: store i8*
+  new __strong id(invalue);
+
+  // CHECK: call noalias i8* @_Znwm
+  // CHECK: call i8* @objc_initWeak
+  new __weak id(invalue);
+
+  // CHECK: call void @objc_release
+  // CHECK: ret void
+}
+
+// CHECK: define void @_Z14test_array_new
+void test_array_new() {
+  // CHECK: call noalias i8* @_Znam
+  // CHECK: store i64 17, i64*
+  // CHECK: call void @llvm.memset.p0i8.i64
+  new strong_id[17];
+
+  // CHECK: call noalias i8* @_Znam
+  // CHECK: store i64 17, i64*
+  // CHECK: call void @llvm.memset.p0i8.i64
+  new weak_id[17];
+  // CHECK: ret void
+}
+
+// CHECK: define void @_Z11test_deletePU8__strongP11objc_objectPU6__weakS0_
+void test_delete(__strong id *sptr, __weak id *wptr) {
+  // CHECK: br i1
+  // CHECK: load i8**
+  // CHECK-NEXT: call void @objc_release
+  // CHECK: call void @_ZdlPv
+  delete sptr;
+
+  // CHECK: call void @objc_destroyWeak
+  // CHECK: call void @_ZdlPv
+  delete wptr;
+
+  // CHECK: ret void
+}
+
+// CHECK: define void @_Z17test_array_deletePU8__strongP11objc_objectPU6__weakS0_
+void test_array_delete(__strong id *sptr, __weak id *wptr) {
+  // CHECK: load i64*
+  // CHECK: {{icmp ne i64.*, 0}}
+  // CHECK: call void @objc_release
+  // CHECK: br label
+  // CHECK: call void @_ZdaPv
+  delete [] sptr;
+
+  // CHECK: load i64*
+  // CHECK: {{icmp ne i64.*, 0}}
+  // CHECK: call void @objc_destroyWeak
+  // CHECK: br label
+  // CHECK: call void @_ZdaPv
+  delete [] wptr;
+}

Added: cfe/trunk/test/CodeGenObjCXX/arc-pseudo-destructors.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/arc-pseudo-destructors.mm?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/arc-pseudo-destructors.mm (added)
+++ cfe/trunk/test/CodeGenObjCXX/arc-pseudo-destructors.mm Wed Jun 15 18:02:42 2011
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-arc -fblocks -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: define void @_Z28test_objc_object_pseudo_dtorPU8__strongP11objc_objectPU6__weakS0_
+void test_objc_object_pseudo_dtor(__strong id *ptr, __weak id *wptr) {
+  // CHECK: load i8***
+  // CHECK-NEXT: load i8** 
+  // CHECK-NEXT: call void @objc_release
+  ptr->~id();
+
+  // CHECK: call void @objc_destroyWeak(i8** {{%.*}})
+  wptr->~id();
+
+  // CHECK: load i8***
+  // CHECK-NEXT: load i8** 
+  // CHECK-NEXT: call void @objc_release
+  (*ptr).~id();
+
+  // CHECK: call void @objc_destroyWeak(i8** {{%.*}})
+  (*wptr).~id();
+  // CHECK: ret void
+}

Added: cfe/trunk/test/CodeGenObjCXX/arc-references.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/arc-references.mm?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/arc-references.mm (added)
+++ cfe/trunk/test/CodeGenObjCXX/arc-references.mm Wed Jun 15 18:02:42 2011
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fblocks -fobjc-arc -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+
+id getObject();
+void callee();
+
+// Lifetime extension for binding a reference to an rvalue
+// CHECK: define void @_Z5test0v()
+void test0() {
+  // CHECK: call i8* @_Z9getObjectv
+  // CHECK-NEXT:: call i8* @objc_retainAutoreleasedReturnValue
+  const __strong id &ref1 = getObject();
+  // CHECK: call void @_Z6calleev
+  callee();
+  // CHECK: call i8* @_Z9getObjectv
+  // CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue
+  // CHECK-NEXT: call i8* @objc_autorelease
+  const __autoreleasing id &ref2 = getObject();
+  // CHECK: call void @_Z6calleev
+  callee();
+  // CHECK: call void @objc_release
+  // CHECK-NEXT: ret
+}
+
+// No lifetime extension when we're binding a reference to an lvalue.
+// CHECK: define void @_Z5test1RU8__strongP11objc_objectRU6__weakS0_
+void test1(__strong id &x, __weak id &y) {
+  // CHECK-NOT: release
+  const __strong id &ref1 = x;
+  const __autoreleasing id &ref2 = x;
+  const __weak id &ref3 = y;
+  // CHECK: ret void
+}
+
+typedef __strong id strong_id;
+
+//CHECK: define void @_Z5test3v
+void test3() {
+  // CHECK: call i8* @objc_initWeak
+  // CHECK-NEXT: store i8**
+  const __weak id &ref = strong_id();
+  // CHECK-NEXT: call void @_Z6calleev()
+  callee();
+  // CHECK-NEXT: call void @objc_destroyWeak
+  // CHECK-NEXT: ret void
+}
+
+// CHECK: define internal void @__cxx_global_var_init(
+// CHECK: call i8* @_Z9getObjectv
+// CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue
+const __strong id &global_ref = getObject();
+
+// Note: we intentionally don't release the object.
+

Added: cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm (added)
+++ cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm Wed Jun 15 18:02:42 2011
@@ -0,0 +1,154 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fobjc-arc -fblocks -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s | FileCheck %s
+
+struct ObjCMember {
+  id member;
+};
+
+struct ObjCArrayMember {
+  id member[2][3];
+};
+
+struct ObjCBlockMember {
+  int (^bp)(int);
+};
+
+// CHECK: define void @_Z42test_ObjCMember_default_construct_destructv(
+void test_ObjCMember_default_construct_destruct() {
+  // CHECK: call void @_ZN10ObjCMemberC1Ev
+  // CHECK: call void @_ZN10ObjCMemberD1Ev
+  ObjCMember m1;
+}
+
+// CHECK: define void @_Z39test_ObjCMember_copy_construct_destruct10ObjCMember
+void test_ObjCMember_copy_construct_destruct(ObjCMember m1) {
+  // CHECK: call void @_ZN10ObjCMemberC1ERKS_
+  // CHECK: call void @_ZN10ObjCMemberD1Ev
+  ObjCMember m2 = m1;
+  // CHECK: ret void
+}
+
+// CHECK: define void @_Z27test_ObjCMember_copy_assign10ObjCMemberS_
+void test_ObjCMember_copy_assign(ObjCMember m1, ObjCMember m2) {
+  // CHECK: {{call.*_ZN10ObjCMemberaSERKS_}}
+  m1 = m2;
+  // CHECK-NEXT: ret void
+}
+
+// Implicitly-generated copy assignment operator for ObjCMember
+// CHECK:    {{define linkonce_odr.*@_ZN10ObjCMemberaSERKS_}}
+// CHECK:      call void @objc_storeStrong
+// CHECK:      ret
+
+// CHECK: define void @_Z47test_ObjCArrayMember_default_construct_destructv
+void test_ObjCArrayMember_default_construct_destruct() {
+  // CHECK: call void @_ZN15ObjCArrayMemberC1Ev
+  ObjCArrayMember m1;
+  // CHECK: call void @_ZN15ObjCArrayMemberD1Ev
+  // CHECK: ret void
+}
+
+// CHECK: define void @_Z44test_ObjCArrayMember_copy_construct_destruct15ObjCArrayMember
+void test_ObjCArrayMember_copy_construct_destruct(ObjCArrayMember m1) {
+  // CHECK: call void @_ZN15ObjCArrayMemberC1ERKS_
+  ObjCArrayMember m2 = m1;
+  // CHECK: call void @_ZN15ObjCArrayMemberD1Ev
+  // CHECK: ret void
+}
+
+void test_ObjCArrayMember_copy_assign(ObjCArrayMember m1, ObjCArrayMember m2) {
+  // CHECK: {{call.*@_ZN15ObjCArrayMemberaSERKS_}}
+  m1 = m2;
+  // CHECK-NEXT: ret void
+}
+
+// Implicitly-generated copy assignment operator for ObjCArrayMember
+// CHECK: {{define linkonce_odr.*@_ZN15ObjCArrayMemberaSERKS_}}
+// CHECK:      call void @objc_storeStrong
+// CHECK-NEXT: br label
+// CHECK: ret
+
+// CHECK: define void @_Z47test_ObjCBlockMember_default_construct_destructv
+void test_ObjCBlockMember_default_construct_destruct() {
+  // CHECK: call void @_ZN15ObjCBlockMemberC1Ev
+  ObjCBlockMember m;
+  // CHECK-NEXT: call void @_ZN15ObjCBlockMemberD1Ev
+  // CHECK-NEXT: ret void
+}
+
+// CHECK: define void @_Z44test_ObjCBlockMember_copy_construct_destruct15ObjCBlockMember
+void test_ObjCBlockMember_copy_construct_destruct(ObjCBlockMember m1) {
+  // CHECK: call void @_ZN15ObjCBlockMemberC1ERKS_
+  ObjCBlockMember m2 = m1;
+  // CHECK-NEXT: call void @_ZN15ObjCBlockMemberD1Ev
+  // CHECK-NEXT: ret void
+}
+
+// CHECK: define void @_Z32test_ObjCBlockMember_copy_assign15ObjCBlockMemberS_
+void test_ObjCBlockMember_copy_assign(ObjCBlockMember m1, ObjCBlockMember m2) {
+  // CHECK: {{call.*_ZN15ObjCBlockMemberaSERKS_}}
+  m1 = m2;
+  // CHECK-NEXT: ret void
+}
+
+// Implicitly-generated copy assignment operator for ObjCBlockMember
+// CHECK:    define linkonce_odr {{%.*}}* @_ZN15ObjCBlockMemberaSERKS_(
+// CHECK:      [[T0:%.*]] = call i8* @objc_retainBlock(
+// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to i32 (i32)*
+// CHECK-NEXT: [[T2:%.*]] = load i32 (i32)** [[SLOT:%.*]],
+// CHECK-NEXT: store i32 (i32)* [[T1]], i32 (i32)** [[SLOT]]
+// CHECK-NEXT: [[T3:%.*]] = bitcast i32 (i32)* [[T2]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[T3]])
+// CHECK-NEXT: ret
+
+// Implicitly-generated copy constructor for ObjCBlockMember
+// CHECK: define linkonce_odr void @_ZN15ObjCBlockMemberC2ERKS_
+// CHECK: call i8* @objc_retainBlock
+// CHECK: ret
+
+// Implicitly-generated destructor for ObjCBlockMember
+// CHECK: define linkonce_odr void @_ZN15ObjCBlockMemberD2Ev
+// CHECK: call void @objc_release(i8*
+// CHECK: ret
+
+// Implicitly-generated default constructor for ObjCBlockMember
+// CHECK: define linkonce_odr void @_ZN15ObjCBlockMemberC2Ev
+// CHECK: store i32 (i32)* null,
+// CHECK-NEXT: ret void
+
+// Implicitly-generated copy constructor for ObjCArrayMember
+// CHECK: define linkonce_odr void @_ZN15ObjCArrayMemberC2ERKS_
+// CHECK: br i1
+// CHECK: call i8* @objc_retain
+// CHECK-NEXT: store i8*
+// CHECK-NEXT: br label
+// CHECK: ret
+
+// Implicitly-generated destructor for ObjCArrayMember
+// CHECK: define linkonce_odr void @_ZN15ObjCArrayMemberD2Ev
+// CHECK: call void @objc_release
+// CHECK: br label
+// CHECK: ret
+
+// Implicitly-generated default constructor for ObjCArrayMember
+// CHECK: define linkonce_odr void @_ZN15ObjCArrayMemberC2Ev
+// CHECK: call void @llvm.memset.p0i8.i64
+// CHECK: ret
+
+// Implicitly-generated copy constructor for ObjCMember
+// CHECK: define linkonce_odr void @_ZN10ObjCMemberC2ERKS_
+// CHECK-NOT: objc_release
+// CHECK: call i8* @objc_retain
+// CHECK-NEXT: store i8*
+// CHECK-NEXT: ret void
+
+// Implicitly-generated destructor for ObjCMember
+// CHECK: define linkonce_odr void @_ZN10ObjCMemberD2Ev
+// CHECK: call void @objc_release
+// CHECK: ret void
+
+// Implicitly-generated default constructor for ObjCMember
+// CHECK: define linkonce_odr void @_ZN10ObjCMemberC2Ev
+// CHECK-NOT: objc_release
+// CHECK: store i8* null
+// CHECK-NEXT: ret void
+

Added: cfe/trunk/test/CodeGenObjCXX/arc.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/arc.mm?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/arc.mm (added)
+++ cfe/trunk/test/CodeGenObjCXX/arc.mm Wed Jun 15 18:02:42 2011
@@ -0,0 +1,152 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fblocks -fobjc-arc -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+
+// rdar://problem/9315552
+// The analogous ObjC testcase test46 in arr.m.
+void test0(__weak id *wp, __weak volatile id *wvp) {
+  extern id test0_helper(void);
+
+  // TODO: this is sub-optimal, we should retain at the actual call site.
+  // TODO: in the non-volatile case, we do not need to be reloading.
+
+  // CHECK:      [[T0:%.*]] = call i8* @_Z12test0_helperv()
+  // CHECK-NEXT: [[T1:%.*]] = load i8*** {{%.*}}, align 8
+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_storeWeak(i8** [[T1]], i8* [[T0]])
+  // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]])
+  // CHECK-NEXT: store i8* [[T3]], i8**
+  id x = *wp = test0_helper();
+
+  // CHECK:      [[T0:%.*]] = call i8* @_Z12test0_helperv()
+  // CHECK-NEXT: [[T1:%.*]] = load i8*** {{%.*}}, align 8
+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_storeWeak(i8** [[T1]], i8* [[T0]])
+  // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_loadWeakRetained(i8** [[T1]])
+  // CHECK-NEXT: store i8* [[T3]], i8**
+  id y = *wvp = test0_helper();
+}
+
+// rdar://problem/9320648
+struct Test1_helper { Test1_helper(); };
+ at interface Test1 @end
+ at implementation Test1 { Test1_helper x; } @end
+// CHECK: define internal i8* @"\01-[Test1 .cxx_construct]"(
+// CHECK:      call void @_ZN12Test1_helperC1Ev(
+// CHECK-NEXT: load
+// CHECK-NEXT: bitcast
+// CHECK-NEXT: ret i8*
+
+void test34(int cond) {
+  __strong id strong;
+  __weak id weak;
+  extern void test34_sink(id *);
+  test34_sink(cond ? &strong : 0);
+  test34_sink(cond ? &weak : 0);
+
+  // CHECK:    define void @_Z6test34i(
+  // CHECK:      [[COND:%.*]] = alloca i32
+  // CHECK-NEXT: [[STRONG:%.*]] = alloca i8*
+  // CHECK-NEXT: [[WEAK:%.*]] = alloca i8*
+  // CHECK-NEXT: [[TEMP1:%.*]] = alloca i8*
+  // CHECK-NEXT: [[TEMP2:%.*]] = alloca i8*
+  // CHECK-NEXT: store i32
+  // CHECK-NEXT: store i8* null, i8** [[STRONG]]
+  // CHECK-NEXT: call i8* @objc_initWeak(i8** [[WEAK]], i8* null)
+
+  // CHECK-NEXT: [[T0:%.*]] = load i32* [[COND]]
+  // CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], 0
+  // CHECK:      [[ARG:%.*]] = phi i8**
+  // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
+  // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i8** null, i8** [[TEMP1]]
+  // CHECK-NEXT: br i1 [[T0]],
+  // CHECK:      [[T0:%.*]] = load i8** [[ARG]]
+  // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP1]]
+  // CHECK-NEXT: br label
+  // CHECK:      call void @_Z11test34_sinkPU15__autoreleasingP11objc_object(i8** [[T1]])
+  // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
+  // CHECK-NEXT: br i1 [[T0]],
+  // CHECK:      [[T0:%.*]] = load i8** [[TEMP1]]
+  // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
+  // CHECK-NEXT: [[T2:%.*]] = load i8** [[ARG]]
+  // CHECK-NEXT: store i8* [[T1]], i8** [[ARG]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T2]])
+  // CHECK-NEXT: br label
+
+  // CHECK:      [[T0:%.*]] = load i32* [[COND]]
+  // CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], 0
+  // CHECK:      [[ARG:%.*]] = phi i8**
+  // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
+  // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i8** null, i8** [[TEMP2]]
+  // CHECK-NEXT: br i1 [[T0]],
+  // CHECK:      [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[ARG]])
+  // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP2]]
+  // CHECK-NEXT: br label
+  // CHECK:      call void @_Z11test34_sinkPU15__autoreleasingP11objc_object(i8** [[T1]])
+  // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
+  // CHECK-NEXT: br i1 [[T0]],
+  // CHECK:      [[T0:%.*]] = load i8** [[TEMP2]]
+  // CHECK-NEXT: call i8* @objc_storeWeak(i8** [[ARG]], i8* [[T0]])
+  // CHECK-NEXT: br label
+
+  // CHECK:      call void @objc_destroyWeak(i8** [[WEAK]])
+  // CHECK:      ret void
+}
+
+struct Test35_Helper {
+  static id makeObject1() __attribute__((ns_returns_retained));
+  id makeObject2() __attribute__((ns_returns_retained));
+  static id makeObject3();
+  id makeObject4();
+};
+
+// CHECK: define void @_Z6test3513Test35_HelperPS_
+void test35(Test35_Helper x0, Test35_Helper *x0p) {
+  // CHECK: call i8* @_ZN13Test35_Helper11makeObject1Ev
+  // CHECK-NOT: call i8* @objc_retain
+  id obj1 = Test35_Helper::makeObject1();
+  // CHECK: call i8* @_ZN13Test35_Helper11makeObject2Ev
+  // CHECK-NOT: call i8* @objc_retain
+  id obj2 = x0.makeObject2();
+  // CHECK: call i8* @_ZN13Test35_Helper11makeObject2Ev
+  // CHECK-NOT: call i8* @objc_retain
+  id obj3 = x0p->makeObject2();
+  id (Test35_Helper::*pmf)() __attribute__((ns_returns_retained))
+    = &Test35_Helper::makeObject2;
+  // CHECK: call i8* %
+  // CHECK-NOT: call i8* @objc_retain
+  id obj4 = (x0.*pmf)();
+  // CHECK: call i8* %
+  // CHECK-NOT: call i8* @objc_retain
+  id obj5 = (x0p->*pmf)();
+
+  // CHECK: call void @objc_release
+  // CHECK: call void @objc_release
+  // CHECK: call void @objc_release
+  // CHECK: call void @objc_release
+  // CHECK: call void @objc_release
+  // CHECK-NEXT: ret void
+}
+
+// CHECK: define void @_Z7test35b13Test35_HelperPS_
+void test35b(Test35_Helper x0, Test35_Helper *x0p) {
+  // CHECK: call i8* @_ZN13Test35_Helper11makeObject3Ev
+  // CHECK: call i8* @objc_retain
+  id obj1 = Test35_Helper::makeObject3();
+  // CHECK: call i8* @_ZN13Test35_Helper11makeObject4Ev
+  // CHECK: call i8* @objc_retain
+  id obj2 = x0.makeObject4();
+  // CHECK: call i8* @_ZN13Test35_Helper11makeObject4Ev
+  // CHECK: call i8* @objc_retain
+  id obj3 = x0p->makeObject4();
+  id (Test35_Helper::*pmf)() = &Test35_Helper::makeObject4;
+  // CHECK: call i8* %
+  // CHECK: call i8* @objc_retain
+  id obj4 = (x0.*pmf)();
+  // CHECK: call i8* %
+  // CHECK: call i8* @objc_retain
+  id obj5 = (x0p->*pmf)();
+
+  // CHECK: call void @objc_release
+  // CHECK: call void @objc_release
+  // CHECK: call void @objc_release
+  // CHECK: call void @objc_release
+  // CHECK: call void @objc_release
+  // CHECK-NEXT: ret void
+}

Added: cfe/trunk/test/CodeGenObjCXX/copy.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/copy.mm?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/copy.mm (added)
+++ cfe/trunk/test/CodeGenObjCXX/copy.mm Wed Jun 15 18:02:42 2011
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+
+// rdar://problem/9158302
+// This should not use a memmove_collectable in non-GC mode.
+namespace test0 {
+  struct A {
+    id x;
+  };
+
+  // CHECK:    define [[A:%.*]]* @_ZN5test04testENS_1AE(
+  // CHECK:      alloca
+  // CHECK-NEXT: getelementptr
+  // CHECK-NEXT: store
+  // CHECK-NEXT: call noalias i8* @_Znwm(
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: call void @llvm.memset.p0i8.i64(
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: bitcast
+  // CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(
+  // CHECK-NEXT: ret
+  A *test(A a) {
+    return new A(a);
+  }
+}
+

Added: cfe/trunk/test/Driver/arc-exceptions.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/arc-exceptions.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/Driver/arc-exceptions.m (added)
+++ cfe/trunk/test/Driver/arc-exceptions.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,5 @@
+// RUN: %clang -### -x objective-c -arch x86_64 -fobjc-arc -fsyntax-only %s 2> %t.log
+// RUN: grep objective-c %t.log
+// RUN: not grep "fobjc-arc-exceptions" %t.log
+// RUN: %clang -### -x objective-c++ -arch x86_64 -fobjc-arc -fsyntax-only %s 2> %t.log
+// RUN: grep "fobjc-arc-exceptions" %t.log

Added: cfe/trunk/test/Driver/arc.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/arc.c?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/Driver/arc.c (added)
+++ cfe/trunk/test/Driver/arc.c Wed Jun 15 18:02:42 2011
@@ -0,0 +1,14 @@
+// RUN: %clang -ObjC -ccc-host-triple i386-apple-darwin9 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -x objective-c -ccc-host-triple i386-apple-darwin9 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -x objective-c++ -ccc-host-triple i386-apple-darwin9 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -x c -ccc-host-triple i386-apple-darwin9 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck -check-prefix NOTOBJC %s
+// RUN: %clang -x c++ -ccc-host-triple i386-apple-darwin9 -m32 -fobjc-arc %s -fsyntax-only 2>&1 | FileCheck -check-prefix NOTOBJC %s
+
+// Just to test clang is working.
+# foo
+
+// CHECK: error: -fobjc-arc is not supported with fragile abi
+// CHECK-NOT: invalid preprocessing directive
+
+// NOTOBJC-NOT: error: -fobjc-arc is not supported with fragile abi
+// NOTOBJC: invalid preprocessing directive

Added: cfe/trunk/test/Driver/ios-simulator-arcruntime.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/ios-simulator-arcruntime.c?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/Driver/ios-simulator-arcruntime.c (added)
+++ cfe/trunk/test/Driver/ios-simulator-arcruntime.c Wed Jun 15 18:02:42 2011
@@ -0,0 +1,5 @@
+// RUN: %clang -### -arch i386 -mmacosx-version-min=10.6 -D__IPHONE_OS_VERSION_MIN_REQUIRED=40201 -fobjc-arc -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS1 %s
+// RUN: %clang -### -arch i386 -mmacosx-version-min=10.6 -D__IPHONE_OS_VERSION_MIN_REQUIRED=50000 -fobjc-arc -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS2 %s
+
+// CHECK-OPTIONS1: -fobjc-no-arc-runtime
+// CHECK-OPTIONS2-NOT: -fobjc-no-arc-runtime

Added: cfe/trunk/test/Driver/no-objc-arr.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/no-objc-arr.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/Driver/no-objc-arr.m (added)
+++ cfe/trunk/test/Driver/no-objc-arr.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,8 @@
+// RUN: %clang  -Werror -fobjc-arc -fsyntax-only -fno-objc-arc -verify %s
+// rdar://8949617
+
+void * FOO() {
+    id string = @"Hello World.\n";
+    void *pointer = string; // No error must be issued
+    return pointer;
+}

Added: cfe/trunk/test/Index/arc-annotate.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/arc-annotate.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/Index/arc-annotate.m (added)
+++ cfe/trunk/test/Index/arc-annotate.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,38 @@
+ at interface A
+ at property (strong, nonatomic) id property;
+ at property (nonatomic, weak) id second_property;
+ at property (unsafe_unretained, nonatomic) id third_property;
+ at end
+
+// RUN: c-index-test -test-annotate-tokens=%s:1:1:5:1 %s -fobjc-arc -fobjc-nonfragile-abi | FileCheck %s
+// CHECK: Punctuation: "@" [1:1 - 1:2] ObjCInterfaceDecl=A:1:12
+// CHECK: Keyword: "interface" [1:2 - 1:11] ObjCInterfaceDecl=A:1:12
+// CHECK: Identifier: "A" [1:12 - 1:13] ObjCInterfaceDecl=A:1:12
+// CHECK: Punctuation: "@" [2:1 - 2:2] ObjCPropertyDecl=property:2:34
+// CHECK: Keyword: "property" [2:2 - 2:10] ObjCPropertyDecl=property:2:34
+// CHECK: Punctuation: "(" [2:11 - 2:12] ObjCPropertyDecl=property:2:34
+// CHECK: Keyword: "strong" [2:12 - 2:18] ObjCPropertyDecl=property:2:34
+// CHECK: Punctuation: "," [2:18 - 2:19] ObjCPropertyDecl=property:2:34
+// CHECK: Keyword: "nonatomic" [2:20 - 2:29] ObjCPropertyDecl=property:2:34
+// CHECK: Punctuation: ")" [2:29 - 2:30] ObjCPropertyDecl=property:2:34
+// CHECK: Identifier: "id" [2:31 - 2:33] TypeRef=id:0:0
+// CHECK: Identifier: "property" [2:34 - 2:42] ObjCPropertyDecl=property:2:34
+// CHECK: Punctuation: ";" [2:42 - 2:43] ObjCInterfaceDecl=A:1:12
+// CHECK: Punctuation: "@" [3:1 - 3:2] ObjCPropertyDecl=second_property:3:32
+// CHECK: Keyword: "property" [3:2 - 3:10] ObjCPropertyDecl=second_property:3:32
+// CHECK: Punctuation: "(" [3:11 - 3:12] ObjCPropertyDecl=second_property:3:32
+// CHECK: Keyword: "nonatomic" [3:12 - 3:21] ObjCPropertyDecl=second_property:3:32
+// CHECK: Punctuation: "," [3:21 - 3:22] ObjCPropertyDecl=second_property:3:32
+// CHECK: Keyword: "weak" [3:23 - 3:27] ObjCPropertyDecl=second_property:3:32
+// CHECK: Punctuation: ")" [3:27 - 3:28] ObjCPropertyDecl=second_property:3:32
+// CHECK: Identifier: "id" [3:29 - 3:31] TypeRef=id:0:0
+// CHECK: Identifier: "second_property" [3:32 - 3:47] ObjCPropertyDecl=second_property:3:32
+// CHECK: Punctuation: "@" [4:1 - 4:2] ObjCPropertyDecl=third_property:4:45
+// CHECK: Keyword: "property" [4:2 - 4:10] ObjCPropertyDecl=third_property:4:45
+// CHECK: Punctuation: "(" [4:11 - 4:12] ObjCPropertyDecl=third_property:4:45
+// CHECK: Keyword: "unsafe_unretained" [4:12 - 4:29] ObjCPropertyDecl=third_property:4:45
+// CHECK: Punctuation: "," [4:29 - 4:30] ObjCPropertyDecl=third_property:4:45
+// CHECK: Keyword: "nonatomic" [4:31 - 4:40] ObjCPropertyDecl=third_property:4:45
+// CHECK: Punctuation: ")" [4:40 - 4:41] ObjCPropertyDecl=third_property:4:45
+// CHECK: Identifier: "id" [4:42 - 4:44] TypeRef=id:0:0
+// CHECK: Identifier: "third_property" [4:45 - 4:59] ObjCPropertyDecl=third_property:4:45

Added: cfe/trunk/test/Index/arc-complete.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/arc-complete.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/Index/arc-complete.m (added)
+++ cfe/trunk/test/Index/arc-complete.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,16 @@
+typedef const void *CFTypeRef;
+
+void test(id x) {
+  (__bridge CFTypeRef)x;
+}
+
+
+
+// RUN: c-index-test -code-completion-at=%s:4:4 %s -fobjc-arc -fobjc-nonfragile-abi | FileCheck -check-prefix=CHECK-CC1 %s
+// CHECK-CC1: macro definition:{TypedText __autoreleasing} (70)
+// CHECK-CC1: NotImplemented:{TypedText __bridge}{HorizontalSpace  }{Placeholder type}{RightParen )}{Placeholder expression} (40)
+// CHECK-CC1: NotImplemented:{TypedText __bridge_retained}{HorizontalSpace  }{Placeholder CF type}{RightParen )}{Placeholder expression} (40)
+// CHECK-CC1: NotImplemented:{TypedText __bridge_transfer}{HorizontalSpace  }{Placeholder Objective-C type}{RightParen )}{Placeholder expression} (40)
+// CHECK-CC1: macro definition:{TypedText __strong} (70)
+// CHECK-CC1: macro definition:{TypedText __unsafe_unretained} (70)
+// CHECK-CC1: macro definition:{TypedText __weak} (70)

Modified: cfe/trunk/test/Index/complete-exprs.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/complete-exprs.m?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/test/Index/complete-exprs.m (original)
+++ cfe/trunk/test/Index/complete-exprs.m Wed Jun 15 18:02:42 2011
@@ -7,10 +7,10 @@
 
 @property int prop1;
 @end
-
+__strong id global;
 @implementation A
 - (int)method:(id)param1 {
-  
+  void foo(id (^block)(id x, A* y));
   for(BOOL B = YES; ; ) { }
 }
 @end
@@ -27,3 +27,8 @@
 // CHECK-CC2: TypedefDecl:{TypedText BOOL} (50)
 // CHECK-CC2: NotImplemented:{TypedText char} (50)
 // CHECK-CC2: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (40)
+// RUN: c-index-test -code-completion-at=%s:15:1 -fobjc-arc -fobjc-nonfragile-abi  %s | FileCheck -check-prefix=CHECK-CC3 %s
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:15:1 -fobjc-arc -fobjc-nonfragile-abi %s | FileCheck -check-prefix=CHECK-CC3 %s
+// CHECK-CC3: FunctionDecl:{ResultType void}{TypedText foo}{LeftParen (}{Placeholder ^id(id x, A *y)block}{RightParen )} (34)
+// CHECK-CC3: VarDecl:{ResultType id}{TypedText global} (50)
+// CHECK-CC3: ParmDecl:{ResultType id}{TypedText param1} (34)

Modified: cfe/trunk/test/Index/complete-property-flags.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/complete-property-flags.m?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/test/Index/complete-property-flags.m (original)
+++ cfe/trunk/test/Index/complete-property-flags.m Wed Jun 15 18:02:42 2011
@@ -16,6 +16,8 @@
 // CHECK-CC1-NEXT: {TypedText readwrite}
 // CHECK-CC1-NEXT: {TypedText retain}
 // CHECK-CC1-NEXT: {TypedText setter}{Text  = }{Placeholder method}
+// CHECK-CC1-NEXT: {TypedText strong}
+// CHECK-CC1-NEXT: {TypedText unsafe_unretained}
 // RUN: c-index-test -code-completion-at=%s:8:18 %s | FileCheck -check-prefix=CHECK-CC2 %s
 // CHECK-CC2: {TypedText getter}{Text  = }{Placeholder method}
 // CHECK-CC2-NEXT: {TypedText nonatomic}

Added: cfe/trunk/test/Lexer/has_feature_objc_arc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Lexer/has_feature_objc_arc.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/Lexer/has_feature_objc_arc.m (added)
+++ cfe/trunk/test/Lexer/has_feature_objc_arc.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -E %s -fobjc-nonfragile-abi -fobjc-arc "-triple" "x86_64-apple-macosx10.7.0" | FileCheck --check-prefix=CHECK-ARC %s
+// RUN: %clang_cc1 -E %s -fobjc-nonfragile-abi -fobjc-arc "-triple" "x86_64-apple-macosx10.6.0" -fobjc-no-arc-runtime | FileCheck --check-prefix=CHECK-ARCLITE %s
+
+#if __has_feature(objc_arc)
+void has_objc_arc_feature();
+#else
+void no_objc_arc_feature();
+#endif
+
+#if __has_feature(objc_arc_weak)
+void has_objc_arc_weak_feature();
+#else
+void no_objc_arc_weak_feature();
+#endif
+
+// CHECK-ARC: void has_objc_arc_feature();
+// CHECK-ARC: void has_objc_arc_weak_feature();
+
+// CHECK-ARCLITE: void has_objc_arc_feature();
+// CHECK-ARCLITE: void no_objc_arc_weak_feature();

Added: cfe/trunk/test/PCH/Inputs/arc.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/Inputs/arc.h?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/PCH/Inputs/arc.h (added)
+++ cfe/trunk/test/PCH/Inputs/arc.h Wed Jun 15 18:02:42 2011
@@ -0,0 +1,20 @@
+// Header for Objective-C ARC-related PCH tests
+
+typedef const void *CFTypeRef;
+typedef const struct __CFString *CFStringRef;
+
+CFTypeRef CFCreateSomething();
+CFStringRef CFCreateString();
+CFTypeRef CFGetSomething();
+CFStringRef CFGetString();
+
+ at interface NSString
+ at end
+
+id CreateSomething();
+NSString *CreateNSString();
+
+typedef int array0[sizeof((__bridge id)CFCreateSomething())];
+typedef int array1[sizeof((__bridge CFTypeRef)CreateSomething())];
+
+

Added: cfe/trunk/test/PCH/arc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/arc.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/PCH/arc.m (added)
+++ cfe/trunk/test/PCH/arc.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,9 @@
+// Test this without pch.
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fobjc-arc -include %S/Inputs/arc.h -fsyntax-only -emit-llvm -o - %s
+
+// Test with pch.
+// RUN: %clang_cc1 -emit-pch -fblocks -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fobjc-arc -x objective-c-header -o %t %S/Inputs/arc.h
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fobjc-arc -include-pch %t -fsyntax-only -emit-llvm -o - %s 
+
+array0 a0;
+array1 a1;

Added: cfe/trunk/test/SemaObjC/Inputs/arc-system-header.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/Inputs/arc-system-header.h?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/Inputs/arc-system-header.h (added)
+++ cfe/trunk/test/SemaObjC/Inputs/arc-system-header.h Wed Jun 15 18:02:42 2011
@@ -0,0 +1,42 @@
+static inline void *test0(id x) {
+  return x;
+}
+
+static inline void **test1(__strong id* x) {
+  return (void**) x;
+}
+
+
+
+
+
+struct Test3 {
+  id *field;
+};
+
+ at interface Test4 {
+ at public
+  id *field1;
+  __strong id *field2;
+}
+ at end
+
+struct Test5 {
+  id field;
+};
+
+
+
+
+
+
+
+extern struct Test6 *const kMagicConstant;
+
+
+
+
+
+ at interface Test7
+ at property id *prop;
+ at end

Added: cfe/trunk/test/SemaObjC/arc-bridged-cast.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/arc-bridged-cast.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/arc-bridged-cast.m (added)
+++ cfe/trunk/test/SemaObjC/arc-bridged-cast.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -fblocks %s
+
+typedef const void *CFTypeRef;
+typedef const struct __CFString *CFStringRef;
+
+ at interface NSString
+ at end
+
+CFTypeRef CFCreateSomething();
+CFStringRef CFCreateString();
+CFTypeRef CFGetSomething();
+CFStringRef CFGetString();
+
+id CreateSomething();
+NSString *CreateNSString();
+
+void from_cf() {
+  id obj1 = (__bridge_transfer id)CFCreateSomething();
+  id obj2 = (__bridge_transfer NSString*)CFCreateString();
+  (__bridge int*)CFCreateSomething(); // expected-error{{incompatible types casting 'CFTypeRef' (aka 'const void *') to 'int *' with a __bridge cast}}
+  id obj3 = (__bridge id)CFGetSomething();
+  id obj4 = (__bridge NSString*)CFGetString();
+}
+
+void to_cf(id obj) {
+  CFTypeRef cf1 = (__bridge_retained CFTypeRef)CreateSomething();
+  CFStringRef cf2 = (__bridge_retained CFStringRef)CreateNSString();
+  CFTypeRef cf3 = (__bridge CFTypeRef)CreateSomething();
+  CFStringRef cf4 = (__bridge CFStringRef)CreateNSString(); 
+}
+
+void fixits() {
+  id obj1 = (id)CFCreateSomething(); // expected-error{{cast of C pointer type 'CFTypeRef' (aka 'const void *') to Objective-C pointer type 'id' requires a bridged cast}} \
+  // expected-note{{use __bridge to convert directly (no change in ownership)}} \
+  // expected-note{{use __bridge_transfer to transfer ownership of a +1 'CFTypeRef' (aka 'const void *') into ARC}}
+  CFTypeRef cf1 = (CFTypeRef)CreateSomething(); // expected-error{{cast of Objective-C pointer type 'id' to C pointer type 'CFTypeRef' (aka 'const void *') requires a bridged cast}} \
+  // expected-note{{use __bridge to convert directly (no change in ownership)}} \
+  // expected-note{{use __bridge_retained to make an ARC object available as a +1 'CFTypeRef' (aka 'const void *')}}
+}

Added: cfe/trunk/test/SemaObjC/arc-decls.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/arc-decls.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/arc-decls.m (added)
+++ cfe/trunk/test/SemaObjC/arc-decls.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-nonfragile-abi -verify %s
+
+// rdar://8843524
+
+struct A {
+    id x; // expected-error {{ARC forbids Objective-C objects in structs or unions}}
+};
+
+union u {
+    id u; // expected-error {{ARC forbids Objective-C objects in structs or unions}}
+};
+
+ at interface I {
+   struct A a; 
+   struct B {
+    id y[10][20]; // expected-error {{ARC forbids Objective-C objects in structs or unions}}
+    id z;
+   } b;
+
+   union u c; 
+};
+ at end
+
+struct S { 
+    id __attribute__((objc_lifetime(none))) i;
+    void * vp;
+    int i1;
+};
+
+// rdar://9046528
+
+ at class NSError;
+
+__autoreleasing id X; // expected-error {{global variables cannot have __autoreleasing lifetime}}
+__autoreleasing NSError *E; // expected-error {{global variables cannot have __autoreleasing lifetime}}
+
+
+extern id __autoreleasing X1; // expected-error {{global variables cannot have __autoreleasing lifetime}}
+
+void func()
+{
+    id X;
+    static id __autoreleasing X1; // expected-error {{global variables cannot have __autoreleasing lifetime}}
+    extern id __autoreleasing E; // expected-error {{global variables cannot have __autoreleasing lifetime}}
+
+}
+
+// rdar://9157348
+
+ at interface J
+ at property (retain) id newFoo; // expected-note {{property declared here}}
+ at property (strong) id copyBar; // expected-note {{property declared here}}
+ at property (copy) id allocBaz; // expected-note {{property declared here}}
+ at property (copy, nonatomic) id new;
+ at end
+
+ at implementation J
+ at synthesize newFoo;	// expected-error {{property's synthesized getter follows Cocoa naming convention for returning}}
+ at synthesize copyBar;	// expected-error {{property's synthesized getter follows Cocoa naming convention for returning}}
+ at synthesize allocBaz;	// expected-error {{property's synthesized getter follows Cocoa naming convention for returning}}
+ at synthesize new;
+- new {return 0; };
+ at end
+

Added: cfe/trunk/test/SemaObjC/arc-no-runtime.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/arc-no-runtime.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/arc-no-runtime.m (added)
+++ cfe/trunk/test/SemaObjC/arc-no-runtime.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fobjc-arc -fobjc-nonfragile-abi -fobjc-no-arc-runtime -verify %s
+
+// rdar://problem/9150784
+void test(void) {
+  __weak id x; // expected-error {{the current deployment target does not support automated __weak references}}
+}
+
+ at interface A
+ at property (weak) id testObjectWeakProperty; // expected-note {{declared here}}
+ at end
+
+ at implementation A
+// rdar://9605088
+ at synthesize testObjectWeakProperty; // expected-error {{the current deployment target does not support automated __weak references}}
+ at end

Added: cfe/trunk/test/SemaObjC/arc-non-pod-memaccess.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/arc-non-pod-memaccess.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/arc-non-pod-memaccess.m (added)
+++ cfe/trunk/test/SemaObjC/arc-non-pod-memaccess.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify -fblocks -triple x86_64-apple-darwin10.0.0 %s
+// RUN: %clang_cc1 -x objective-c++ -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify -fblocks -triple x86_64-apple-darwin10.0.0 %s
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *memset(void *, int, __SIZE_TYPE__);
+void *memmove(void *s1, const void *s2, __SIZE_TYPE__ n);
+void *memcpy(void *s1, const void *s2, __SIZE_TYPE__ n);
+
+#ifdef __cplusplus
+}
+#endif
+
+void test(id __strong *sip, id __weak *wip, id __autoreleasing *aip,
+          id __unsafe_unretained *uip, void *ptr) {
+  // All okay.
+  memset(sip, 0, 17);
+  memset(wip, 0, 17);
+  memset(aip, 0, 17);
+  memset(uip, 0, 17);
+
+  memcpy(sip, ptr, 17); // expected-warning{{destination for this 'memcpy' call is a pointer to lifetime-qualified type}} \
+                      // expected-note{{explicitly cast the pointer to silence this warning}}
+  memcpy(wip, ptr, 17); // expected-warning{{destination for this 'memcpy' call is a pointer to lifetime-qualified type}} \
+                      // expected-note{{explicitly cast the pointer to silence this warning}}
+  memcpy(aip, ptr, 17); // expected-warning{{destination for this 'memcpy' call is a pointer to lifetime-qualified type}} \
+                      // expected-note{{explicitly cast the pointer to silence this warning}}
+  memcpy(uip, ptr, 17);
+
+  memcpy(ptr, sip, 17); // expected-warning{{source of this 'memcpy' call is a pointer to lifetime-qualified type}} \
+                      // expected-note{{explicitly cast the pointer to silence this warning}}
+  memcpy(ptr, wip, 17); // expected-warning{{source of this 'memcpy' call is a pointer to lifetime-qualified type}} \
+                      // expected-note{{explicitly cast the pointer to silence this warning}}
+  memcpy(ptr, aip, 17); // expected-warning{{source of this 'memcpy' call is a pointer to lifetime-qualified type}} \
+                      // expected-note{{explicitly cast the pointer to silence this warning}}
+  memcpy(ptr, uip, 17);
+
+  memmove(sip, ptr, 17); // expected-warning{{destination for this 'memmove' call is a pointer to lifetime-qualified type}} \
+                      // expected-note{{explicitly cast the pointer to silence this warning}}
+  memmove(wip, ptr, 17); // expected-warning{{destination for this 'memmove' call is a pointer to lifetime-qualified type}} \
+                      // expected-note{{explicitly cast the pointer to silence this warning}}
+  memmove(aip, ptr, 17); // expected-warning{{destination for this 'memmove' call is a pointer to lifetime-qualified type}} \
+                      // expected-note{{explicitly cast the pointer to silence this warning}}
+  memmove(uip, ptr, 17);
+
+  memmove(ptr, sip, 17); // expected-warning{{source of this 'memmove' call is a pointer to lifetime-qualified type}} \
+                      // expected-note{{explicitly cast the pointer to silence this warning}}
+  memmove(ptr, wip, 17); // expected-warning{{source of this 'memmove' call is a pointer to lifetime-qualified type}} \
+                      // expected-note{{explicitly cast the pointer to silence this warning}}
+  memmove(ptr, aip, 17); // expected-warning{{source of this 'memmove' call is a pointer to lifetime-qualified type}} \
+                      // expected-note{{explicitly cast the pointer to silence this warning}}
+  memmove(ptr, uip, 17);
+}

Added: cfe/trunk/test/SemaObjC/arc-property-decl-attrs.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/arc-property-decl-attrs.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/arc-property-decl-attrs.m (added)
+++ cfe/trunk/test/SemaObjC/arc-property-decl-attrs.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,67 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify %s
+// rdar://9340606
+
+ at interface Foo {
+ at public
+    id __unsafe_unretained x;
+    id __weak y;
+    id __autoreleasing z; // expected-error {{ivars cannot have __autoreleasing lifetime}}
+}
+ at property(strong) id x;
+ at property(strong) id y;
+ at property(strong) id z;
+ at end
+
+ at interface Bar {
+ at public
+    id __unsafe_unretained x;
+    id __weak y;
+    id __autoreleasing z; // expected-error {{ivars cannot have __autoreleasing lifetime}}
+}
+ at property(retain) id x;
+ at property(retain) id y;
+ at property(retain) id z;
+ at end
+
+ at interface Bas {
+ at public
+    id __unsafe_unretained x;
+    id __weak y;
+    id __autoreleasing z; // expected-error {{ivars cannot have __autoreleasing lifetime}}
+}
+ at property(copy) id x;
+ at property(copy) id y;
+ at property(copy) id z;
+ at end
+
+// Errors should start about here :-)
+
+ at interface Bat 
+ at property(strong) __unsafe_unretained id x; // expected-error {{strong property 'x' may not also be declared __unsafe_unretained}}
+ at property(strong) __weak id y; // expected-error {{strong property 'y' may not also be declared __weak}} expected-error {{property attributes 'strong' and 'weak' are mutually exclusive}}
+ at property(strong) __autoreleasing id z; // expected-error {{strong property 'z' may not also be declared __autoreleasing}}
+ at end
+
+ at interface Bau
+ at property(retain) __unsafe_unretained id x; // expected-error {{strong property 'x' may not also be declared __unsafe_unretained}}
+ at property(retain) __weak id y; // expected-error {{strong property 'y' may not also be declared __weak}} expected-error {{property attributes 'retain' and 'weak' are mutually exclusive}}
+ at property(retain) __autoreleasing id z; // expected-error {{strong property 'z' may not also be declared __autoreleasing}}
+ at end
+
+ at interface Bav 
+ at property(copy) __unsafe_unretained id x; // expected-error {{strong property 'x' may not also be declared __unsafe_unretained}}
+ at property(copy) __weak id y; // expected-error {{strong property 'y' may not also be declared __weak}} expected-error {{property attributes 'copy' and 'weak' are mutually exclusive}}
+ at property(copy) __autoreleasing id z; // expected-error {{strong property 'z' may not also be declared __autoreleasing}}
+ at end
+
+ at interface Bingo 
+ at property(assign) __unsafe_unretained id x;
+ at property(assign) __weak id y; // expected-error {{property attributes 'assign' and 'weak' are mutually exclusive}}
+ at property(assign) __autoreleasing id z; // expected-error {{unsafe_unretained property 'z' may not also be declared __autoreleasing}}
+ at end
+
+ at interface Batman 
+ at property(unsafe_unretained) __unsafe_unretained id x;
+ at property(unsafe_unretained) __weak id y; // expected-error {{property attributes 'unsafe_unretained' and 'weak' are mutually exclusive}}
+ at property(unsafe_unretained) __autoreleasing id z; // expected-error {{unsafe_unretained property 'z' may not also be declared __autoreleasing}}
+ at end

Added: cfe/trunk/test/SemaObjC/arc-property-lifetime.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/arc-property-lifetime.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/arc-property-lifetime.m (added)
+++ cfe/trunk/test/SemaObjC/arc-property-lifetime.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,112 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify %s
+// rdar://9340606
+
+ at interface Foo {
+ at public
+    id __unsafe_unretained x;
+    id __weak y;
+    id __autoreleasing z; // expected-error {{ivars cannot have __autoreleasing lifetime}}
+}
+ at property(strong) id x; // expected-note {{property declared here}}
+ at property(strong) id y; // expected-note {{property declared here}}
+ at property(strong) id z;
+ at end
+
+ at implementation Foo
+ at synthesize x; // expected-error {{existing ivar 'x' for strong property 'x' may not be __unsafe_unretained}}
+ at synthesize y; // expected-error {{existing ivar 'y' for strong property 'y' may not be __weak}}
+ at synthesize z; // suppressed
+ at end
+
+ at interface Bar {
+ at public
+    id __unsafe_unretained x;
+    id __weak y;
+    id __autoreleasing z; // expected-error {{ivars cannot have __autoreleasing lifetime}}
+}
+ at property(retain) id x; // expected-note {{property declared here}}
+ at property(retain) id y; // expected-note {{property declared here}}
+ at property(retain) id z;
+ at end
+
+ at implementation Bar
+ at synthesize x; // expected-error {{existing ivar 'x' for strong property 'x' may not be __unsafe_unretained}}
+ at synthesize y; // expected-error {{existing ivar 'y' for strong property 'y' may not be __weak}}
+ at synthesize z; // suppressed
+ at end
+
+ at interface Bas {
+ at public
+    id __unsafe_unretained x;
+    id __weak y;
+    id __autoreleasing z; // expected-error {{ivars cannot have __autoreleasing lifetime}}
+}
+ at property(copy) id x; // expected-note {{property declared here}}
+ at property(copy) id y; // expected-note {{property declared here}} 
+ at property(copy) id z;
+ at end
+
+ at implementation Bas
+ at synthesize x; // expected-error {{existing ivar 'x' for strong property 'x' may not be __unsafe_unretained}}
+ at synthesize y; // expected-error {{existing ivar 'y' for strong property 'y' may not be __weak}}
+ at synthesize z; // suppressed
+ at end
+
+ at interface Bat 
+ at property(strong) __unsafe_unretained id x; // expected-error {{strong property 'x' may not also be declared __unsafe_unretained}}
+ at property(strong) __autoreleasing id z; // expected-error {{strong property 'z' may not also be declared __autoreleasing}}
+ at end
+
+ at interface Bau 
+ at property(retain) __unsafe_unretained id x; // expected-error {{strong property 'x' may not also be declared __unsafe_unretained}}
+ at property(retain) __autoreleasing id z; // expected-error {{strong property 'z' may not also be declared __autoreleasing}}
+ at end
+
+ at interface Bav 
+ at property(copy) __unsafe_unretained id x; // expected-error {{strong property 'x' may not also be declared __unsafe_unretained}}
+ at property(copy) __autoreleasing id z; // expected-error {{strong property 'z' may not also be declared __autoreleasing}}
+ at end
+
+// rdar://9341593
+ at interface Gorf  {
+   id __unsafe_unretained x;
+   id y;
+}
+ at property(assign) id __unsafe_unretained x;
+ at property(assign) id y; // expected-note {{property declared here}}
+ at property(assign) id z;
+ at end
+
+ at implementation Gorf
+ at synthesize x;
+ at synthesize y; // expected-error {{existing ivar 'y' for unsafe_unretained property 'y' must be __unsafe_unretained}}
+ at synthesize z;
+ at end
+
+ at interface Gorf2  {
+   id __unsafe_unretained x;
+   id y;
+}
+ at property(unsafe_unretained) id __unsafe_unretained x;
+ at property(unsafe_unretained) id y; // expected-note {{property declared here}}
+ at property(unsafe_unretained) id z;
+ at end
+
+ at implementation Gorf2
+ at synthesize x;
+ at synthesize y; // expected-error {{existing ivar 'y' for unsafe_unretained property 'y' must be __unsafe_unretained}}
+ at synthesize z;
+ at end
+
+// rdar://9355230
+ at interface I {
+  char _isAutosaving;
+}
+ at property char isAutosaving;
+
+ at end
+
+ at implementation I
+ at synthesize isAutosaving = _isAutosaving;
+ at end
+

Added: cfe/trunk/test/SemaObjC/arc-property.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/arc-property.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/arc-property.m (added)
+++ cfe/trunk/test/SemaObjC/arc-property.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -fblocks -verify %s
+// rdar://9309489
+
+ at interface MyClass {
+        id __weak myString;
+        id StrongIvar;
+        id __weak myString2;
+        id __weak myString3;
+        id StrongIvar5;
+}
+ at property (strong) id myString; // expected-note {{property declared here}}
+ at property (strong) id myString1;
+ at property (retain) id myString2; // expected-note {{property declared here}}
+//
+ at property (weak) id myString3;
+ at property (weak) id myString4;
+ at property __weak id myString5; // expected-note {{property declared here}}
+ at end
+
+ at implementation MyClass
+ at synthesize myString; // expected-error {{existing ivar 'myString' for strong property 'myString' may not be __weak}}
+ at synthesize myString1 = StrongIvar; // OK
+ at synthesize myString2 = myString2; // expected-error {{existing ivar 'myString2' for strong property 'myString2' may not be __weak}}
+//
+ at synthesize myString3; // OK
+ at synthesize myString4; // OK
+ at synthesize myString5 = StrongIvar5; // expected-error {{existing ivar 'StrongIvar5' for __weak property 'myString5' must be __weak}}
+
+ at end
+
+// rdar://9340692
+ at interface Foo {
+ at public
+    id __unsafe_unretained x;   // should be __weak
+    id __strong y;
+    id __autoreleasing z; // expected-error {{ivars cannot have __autoreleasing lifetime}}
+}
+ at property(weak) id x; // expected-note {{property declared here}}
+ at property(weak) id y; // expected-note {{property declared here}}
+ at property(weak) id z;
+ at end
+
+ at implementation Foo
+ at synthesize x;	// expected-error {{existing ivar 'x' for __weak property 'x' must be __weak}}
+ at synthesize y;	// expected-error {{existing ivar 'y' for __weak property 'y' must be __weak}}
+ at synthesize z;  // suppressed
+ at end
+

Added: cfe/trunk/test/SemaObjC/arc-system-header.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/arc-system-header.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/arc-system-header.m (added)
+++ cfe/trunk/test/SemaObjC/arc-system-header.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,48 @@
+// silly workaround expected-note {{marked unavailable here}}
+// RUN: %clang_cc1 -fobjc-arc -fobjc-nonfragile-abi -isystem %S/Inputs %s -DNO_USE
+// RUN: %clang_cc1 -fobjc-arc -fobjc-nonfragile-abi -isystem %S/Inputs %s -verify
+
+// another silly workaround expected-note {{marked unavailable here}}
+#include <arc-system-header.h>
+
+#ifndef NO_USE
+void test(id op, void *cp) {
+  cp = test0(op); // expected-error {{'test0' is unavailable: converts between Objective-C and C pointers in -fobjc-arc}}
+  cp = *test1(&op); // expected-error {{'test1' is unavailable: converts between Objective-C and C pointers in -fobjc-arc}}
+}
+
+// workaround expected-note {{marked unavailable here}}
+void test3(struct Test3 *p) {
+  p->field = 0; // expected-error {{'field' is unavailable: this system declaration uses an unsupported type}}
+}
+
+// workaround expected-note {{marked unavailable here}}
+void test4(Test4 *p) {
+  p->field1 = 0; // expected-error {{'field1' is unavailable: this system declaration uses an unsupported type}}
+  p->field2 = 0;
+}
+
+// workaround expected-note {{marked unavailable here}}
+void test5(struct Test5 *p) {
+  p->field = 0; // expected-error {{'field' is unavailable: this system field has retaining lifetime}}
+}
+
+id test6() {
+  // This is actually okay to use if declared in a system header.
+  id x;
+  x = (id) kMagicConstant;
+  x = (id) (x ? kMagicConstant : kMagicConstant);
+  x = (id) (x ? kMagicConstant : (void*) 0);
+
+  extern void test6_helper();
+  x = (id) (test6_helper(), kMagicConstant);
+}
+
+// workaround expected-note 4 {{marked unavailable here}}
+void test7(Test7 *p) {
+  *p.prop = 0; // expected-error {{'prop' is unavailable: this system declaration uses an unsupported type}}
+  p.prop = 0; // expected-error {{'prop' is unavailable: this system declaration uses an unsupported type}}
+  *[p prop] = 0; // expected-error {{'prop' is unavailable: this system declaration uses an unsupported type}}
+  [p setProp: 0]; // expected-error {{'setProp:' is unavailable: this system declaration uses an unsupported type}}
+}
+#endif

Added: cfe/trunk/test/SemaObjC/arc-type-conversion.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/arc-type-conversion.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/arc-type-conversion.m (added)
+++ cfe/trunk/test/SemaObjC/arc-type-conversion.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-nonfragile-abi -verify %s
+
+void * cvt(id arg)
+{
+  void* voidp_val;
+  (void)(int*)arg; // expected-error {{cast of an Objective-C pointer to 'int *' is disallowed with ARC}}
+  (void)(id)arg;
+  (void)(__autoreleasing id*)arg; // expected-error {{cast of an Objective-C pointer to '__autoreleasing id *' is disallowed with ARC}}
+  (void)(id*)arg; // expected-error {{pointer to non-const type 'id' with no explicit lifetime}} expected-error {{cast of an Objective-C pointer to '__autoreleasing id *' is disallowed with ARC}}
+
+  (void)(__autoreleasing id**)voidp_val;
+  (void)(void*)voidp_val;
+  (void)(void**)arg; // expected-error {{cast of an Objective-C pointer to 'void **' is disallowed with ARC}}
+  cvt((void*)arg); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'void *' requires a bridged cast}} \
+                   // expected-error {{implicit conversion of a non-Objective-C pointer type 'void *' to 'id' is disallowed with ARC}} \
+                   // expected-note{{use __bridge to convert directly (no change in ownership)}} \
+                   // expected-note{{use __bridge_retained to make an ARC object available as a +1 'void *'}}
+  cvt(0);
+  (void)(__strong id**)(0);
+  return arg; // expected-error {{implicit conversion of an Objective-C pointer to 'void *' is disallowed with ARC}}
+}
+
+void to_void(__strong id *sip, __weak id *wip,
+             __autoreleasing id *aip,
+             __unsafe_unretained id *uip) {
+  void *vp1 = sip;
+  void *vp2 = wip;
+  void *vp3 = aip;
+  void *vp4 = uip;
+  (void)(void*)sip;
+  (void)(void*)wip;
+  (void)(void*)aip;
+  (void)(void*)uip;
+  (void)(void*)&sip;
+  (void)(void*)&wip;
+  (void)(void*)&aip;
+  (void)(void*)&uip;
+}
+
+void from_void(void *vp) {
+  __strong id *sip = (__strong id *)vp;
+  __weak id *wip = (__weak id *)vp;
+  __autoreleasing id *aip = (__autoreleasing id *)vp;
+  __unsafe_unretained id *uip = (__unsafe_unretained id *)vp;
+
+  __strong id **sipp = (__strong id **)vp;
+  __weak id **wipp = (__weak id **)vp;
+  __autoreleasing id **aipp = (__autoreleasing id **)vp;
+  __unsafe_unretained id **uipp = (__unsafe_unretained id **)vp;
+
+  sip = vp; // expected-error{{implicit conversion of a non-Objective-C pointer type 'void *' to '__strong id *' is disallowed with ARC}}
+  wip = vp; // expected-error{{implicit conversion of a non-Objective-C pointer type 'void *' to '__weak id *' is disallowed with ARC}}
+  aip = vp; // expected-error{{implicit conversion of a non-Objective-C pointer type 'void *' to '__autoreleasing id *' is disallowed with ARC}}
+  uip = vp; // expected-error{{implicit conversion of a non-Objective-C pointer type 'void *' to '__unsafe_unretained id *' is disallowed with ARC}}
+}

Added: cfe/trunk/test/SemaObjC/arc-unsafe_unretained.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/arc-unsafe_unretained.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/arc-unsafe_unretained.m (added)
+++ cfe/trunk/test/SemaObjC/arc-unsafe_unretained.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -fobjc-nonfragile-abi %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -fobjc-nonfragile-abi -fobjc-arc %s
+
+struct X {
+  __unsafe_unretained id object;
+  int (^ __unsafe_unretained block)(int, int);
+};
+
+void f(struct X x) {
+  x.object = 0;
+  x.block = ^(int x, int y) { return x + y; };
+}

Added: cfe/trunk/test/SemaObjC/arc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/arc.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/arc.m (added)
+++ cfe/trunk/test/SemaObjC/arc.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,550 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -fblocks -verify %s
+
+typedef unsigned long NSUInteger;
+
+void test0(void (*fn)(int), int val) {
+  fn(val);
+}
+
+ at interface A
+- (id)retain;
+- (id)autorelease;
+- (oneway void)release;
+- (void)dealloc;
+- (NSUInteger)retainCount;
+ at end
+
+void test1(A *a) {
+  SEL s = @selector(retain);	// expected-error {{ARC forbids use of 'retain' in a @selector}}
+  s = @selector(release);	// expected-error {{ARC forbids use of 'release' in a @selector}}
+  s = @selector(autorelease);	// expected-error {{ARC forbids use of 'autorelease' in a @selector}}
+  s = @selector(dealloc);	// expected-error {{ARC forbids use of 'dealloc' in a @selector}}
+  [a dealloc]; // expected-error {{ARC forbids explicit message send of 'dealloc'}}
+  [a retain]; // expected-error {{ARC forbids explicit message send of 'retain'}}
+  [a retainCount]; // expected-error {{ARC forbids explicit message send of 'retainCount'}}
+  [a release]; // expected-error {{ARC forbids explicit message send of 'release'}}
+  [a autorelease]; // expected-error {{ARC forbids explicit message send of 'autorelease'}}
+}
+
+ at interface Test2 : A
+- (void) dealloc;
+ at end
+ at implementation Test2
+- (void) dealloc {
+  // This should maybe just be ignored.  We're just going to warn about it for now.
+  [super dealloc]; // expected-error {{ARC forbids explicit message send of 'dealloc'}}
+}
+ at end
+
+__weak __strong id x; // expected-error {{the type '__strong id' already has retainment attributes}}
+
+// rdar://8843638
+
+ at interface I
+- (id)retain;
+- (id)autorelease;
+- (oneway void)release;
+- (NSUInteger)retainCount;
+ at end
+
+ at implementation I
+- (id)retain{return 0;} // expected-error {{ARC forbids implementation of 'retain'}}
+- (id)autorelease{return 0;} // expected-error {{ARC forbids implementation of 'autorelease'}}
+- (oneway void)release{} // expected-error {{ARC forbids implementation of 'release'}}
+- (NSUInteger)retainCount{ return 0; } // expected-error {{ARC forbids implementation of 'retainCount'}}
+ at end
+
+ at implementation I(CAT)
+- (id)retain{return 0;} // expected-error {{ARC forbids implementation of 'retain'}}
+- (id)autorelease{return 0;} // expected-error {{ARC forbids implementation of 'autorelease'}}
+- (oneway void)release{} // expected-error {{ARC forbids implementation of 'release'}}
+- (NSUInteger)retainCount{ return 0; } // expected-error {{ARC forbids implementation of 'retainCount'}}
+ at end
+
+// rdar://8861761
+
+ at interface B
+-(id)alloc;
+- (id)initWithInt: (int) i;
+ at end
+
+void rdar8861761() {
+  B *o1 = [[B alloc] initWithInt:0];
+  B *o2 = [B alloc];
+  [o2 initWithInt:0]; // expected-warning {{expression result unused}}
+}
+
+// rdar://8925835
+ at interface rdar8925835
+- (void)foo:(void (^)(unsigned captureCount, I * const capturedStrings[captureCount]))block;
+ at end
+
+void test5() {
+  extern void test5_helper(__autoreleasing id *);
+  id x;
+
+  // Okay because of magic temporaries.
+  test5_helper(&x);
+
+  __autoreleasing id *a = &x; // expected-error {{initializing '__autoreleasing id *' with an expression of type '__strong id *' changes retain/release properties of pointer}}
+
+  a = &x; // expected-error {{assigning '__strong id *' to '__autoreleasing id *' changes retain/release properties of pointer}}
+
+  extern void test5_helper2(id const *);
+  test5_helper2(&x);
+
+  extern void test5_helper3(__weak id *); // expected-note {{passing argument to parameter here}}
+  test5_helper3(&x); // expected-error {{passing '__strong id *' to parameter of type '__weak id *' changes retain/release properties of pointer}}
+}
+
+// rdar://problem/8937869
+void test6(unsigned cond) {
+  switch (cond) {
+  case 0:
+    ;
+    id x; // expected-note {{jump bypasses initialization of retaining variable}}
+
+  case 1: // expected-error {{switch case is in protected scope}}
+    break;
+  }
+}
+
+ at class NSError;
+void test7(void) {
+  extern void test7_helper(NSError **);
+  NSError *err;
+  test7_helper(&err);
+}
+void test7_weak(void) {
+  extern void test7_helper(NSError **);
+  __weak NSError *err;
+  test7_helper(&err);
+}
+void test7_unsafe(void) {
+  extern void test7_helper(NSError **); // expected-note {{passing argument to parameter here}}
+  __unsafe_unretained NSError *err;
+  test7_helper(&err); // expected-error {{passing 'NSError *__unsafe_unretained *' to parameter of type 'NSError *__autoreleasing *' changes retain/release properties of pointer}}
+}
+
+ at class Test8_incomplete;
+ at interface Test8_complete @end;
+ at interface Test8_super @end;
+ at interface Test8 : Test8_super
+- (id) init00;
+- (id) init01; // expected-note {{declaration in interface}} \
+               // expected-note{{overridden method}}
+- (id) init02; // expected-note{{overridden method}}
+- (id) init03; // covariance
+- (id) init04; // covariance
+- (id) init05; // expected-note{{overridden method}}
+
+- (void) init10; // expected-note {{declaration in interface is not in the 'init' family because its result type is not an object pointer}}
+- (void) init11;
+- (void) init12;
+- (void) init13; // expected-note {{declaration in interface is not in the 'init' family because its result type is not an object pointer}}
+- (void) init14; // expected-note {{declaration in interface is not in the 'init' family because its result type is not an object pointer}}
+- (void) init15;
+
+// These should be invalid to actually call.
+- (Test8_incomplete*) init20;
+- (Test8_incomplete*) init21; // expected-note {{declaration in interface}}
+- (Test8_incomplete*) init22;
+- (Test8_incomplete*) init23;
+- (Test8_incomplete*) init24;
+- (Test8_incomplete*) init25;
+
+- (Test8_super*) init30; // id exception to covariance
+- (Test8_super*) init31; // expected-note {{declaration in interface}} \
+                         // expected-note{{overridden method}}
+- (Test8_super*) init32; // expected-note{{overridden method}}
+- (Test8_super*) init33;
+- (Test8_super*) init34; // covariance
+- (Test8_super*) init35; // expected-note{{overridden method}}
+
+- (Test8*) init40; // id exception to covariance
+- (Test8*) init41; // expected-note {{declaration in interface}} \
+                   // expected-note{{overridden method}}
+- (Test8*) init42; // expected-note{{overridden method}}
+- (Test8*) init43; // this should be a warning, but that's a general language thing, not an ARC thing
+- (Test8*) init44;
+- (Test8*) init45; // expected-note{{overridden method}}
+
+- (Test8_complete*) init50; // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init51; // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init52; // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init53; // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init54; // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init55; // expected-error {{init methods must return a type related to the receiver type}}
+ at end
+ at implementation Test8
+- (id) init00 { return 0; }
+- (id) init10 { return 0; } // expected-error {{method implementation does not match its declaration}}
+- (id) init20 { return 0; }
+- (id) init30 { return 0; }
+- (id) init40 { return 0; }
+- (id) init50 { return 0; }
+
+- (void) init01 {} // expected-error {{method was declared as an 'init' method, but its implementation doesn't match because its result type is not an object pointer}} \
+                   // expected-warning{{ method is expected to return an instance of its class type 'Test8', but is declared to return 'void'}}
+- (void) init11 {}
+- (void) init21 {} // expected-error {{method was declared as an 'init' method, but its implementation doesn't match because its result type is not an object pointer}}
+- (void) init31 {} // expected-error {{method was declared as an 'init' method, but its implementation doesn't match because its result type is not an object pointer}} \
+                   // expected-warning{{ method is expected to return an instance of its class type 'Test8', but is declared to return 'void'}}
+- (void) init41 {} // expected-error {{method was declared as an 'init' method, but its implementation doesn't match because its result type is not an object pointer}} \
+                   // expected-warning{{ method is expected to return an instance of its class type 'Test8', but is declared to return 'void'}}
+- (void) init51 {}
+
+- (Test8_incomplete*) init02 { return 0; } // expected-error {{init methods must return a type related to the receiver type}} \
+                                           // expected-warning{{method is expected to return an instance of its class type 'Test8', but is declared to return 'Test8_incomplete *'}}
+- (Test8_incomplete*) init12 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_incomplete*) init22 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_incomplete*) init32 { return 0; } // expected-error {{init methods must return a type related to the receiver type}} \
+                                           // expected-warning{{method is expected to return an instance of its class type 'Test8', but is declared to return 'Test8_incomplete *'}}
+- (Test8_incomplete*) init42 { return 0; } // expected-error {{init methods must return a type related to the receiver type}} \
+                                           // expected-warning{{method is expected to return an instance of its class type 'Test8', but is declared to return 'Test8_incomplete *'}}
+- (Test8_incomplete*) init52 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+
+- (Test8_super*) init03 { return 0; }
+- (Test8_super*) init13 { return 0; } // expected-error {{method implementation does not match its declaration}}
+- (Test8_super*) init23 { return 0; }
+- (Test8_super*) init33 { return 0; }
+- (Test8_super*) init43 { return 0; }
+- (Test8_super*) init53 { return 0; }
+
+- (Test8*) init04 { return 0; }
+- (Test8*) init14 { return 0; } // expected-error {{method implementation does not match its declaration}}
+- (Test8*) init24 { return 0; }
+- (Test8*) init34 { return 0; }
+- (Test8*) init44 { return 0; }
+- (Test8*) init54 { return 0; }
+
+- (Test8_complete*) init05 { return 0; } // expected-error {{init methods must return a type related to the receiver type}} \
+                                         // expected-warning{{method is expected to return an instance of its class type 'Test8', but is declared to return 'Test8_complete *'}}
+- (Test8_complete*) init15 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init25 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init35 { return 0; } // expected-error {{init methods must return a type related to the receiver type}} \
+                                         // expected-warning{{method is expected to return an instance of its class type 'Test8', but is declared to return 'Test8_complete *'}}
+- (Test8_complete*) init45 { return 0; } // expected-error {{init methods must return a type related to the receiver type}} \
+                                         // expected-warning{{method is expected to return an instance of its class type 'Test8', but is declared to return 'Test8_complete *'}}
+- (Test8_complete*) init55 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+ at end
+
+ at class Test9_incomplete;
+ at interface Test9
+- (Test9_incomplete*) init1; // expected-error {{init methods must return a type related to the receiver type}}
+- (Test9_incomplete*) init2;
+ at end
+id test9(Test9 *v) {
+  return [v init1];
+}
+
+// Test that the inference rules are different for fast enumeration variables.
+void test10(id collection) {
+  for (id x in collection) {
+    __strong id *ptr = &x; // expected-error {{initializing '__strong id *' with an expression of type 'const __unsafe_unretained id *' changes retain/release properties of pointer}}
+  }
+
+  for (__strong id x in collection) {
+    __weak id *ptr = &x; // expected-error {{initializing '__weak id *' with an expression of type '__strong id *' changes retain/release properties of pointer}}
+  }
+}
+
+// rdar://problem/9078626
+#define nil ((void*) 0)
+void test11(id op, void *vp) {
+  _Bool b;
+  b = (op == nil);
+  b = (nil == op);
+
+  b = (vp == nil);
+  b = (nil == vp);
+
+  b = (vp == op); // expected-error {{implicit conversion of an Objective-C pointer to 'void *'}}
+  b = (op == vp); // expected-error {{implicit conversion of a non-Objective-C pointer type 'void *' to 'id'}}
+}
+
+void test12(id collection) {
+  for (id x in collection) {
+    x = 0; // expected-error {{fast enumeration variables can't be modified in ARC by default; declare the variable __strong to allow this}}
+  }
+
+  for (const id x in collection) {
+    x = 0; // expected-error {{read-only variable is not assignable}}
+  }
+
+  for (__strong id x in collection) {
+    x = 0;
+  }
+}
+
+ at interface Test13
+- (id) init0;
+- (void) noninit;
+ at end
+ at implementation Test13
+- (id) init0 {
+  self = 0;
+}
+- (void) noninit {
+  self = 0; // expected-error {{cannot assign to 'self' outside of a method in the init family}}
+}
+ at end
+
+// rdar://problem/9172151
+ at class Test14A, Test14B;
+void test14() {
+  extern void test14_consume(id *);
+  extern int test14_cond(void);
+  extern float test14_nowriteback(id __autoreleasing const *); // expected-note{{passing argument to parameter here}}
+
+  Test14A *a;
+  Test14B *b;
+  id i;
+  id cla[10];
+  id vla[test14_cond() + 10];
+
+  test14_consume((__strong id*) &a);
+  test14_consume((test14_cond() ? (__strong id*) &b : &i));
+  test14_consume(test14_cond() ? 0 : &a);
+  test14_consume(test14_cond() ? (void*) 0 : (&a));
+  test14_consume(cla); // expected-error {{passing address of non-scalar object to __autoreleasing parameter for write-back}}
+  test14_consume(vla); // expected-error {{passing address of non-scalar object to __autoreleasing parameter for write-back}}
+  test14_consume(&cla[5]); // expected-error {{passing address of non-scalar object to __autoreleasing parameter for write-back}}
+
+  __strong id *test14_indirect(void);
+  test14_consume(test14_indirect()); // expected-error {{passing address of non-local object to __autoreleasing parameter for write-back}}
+
+  extern id test14_global;
+  test14_consume(&test14_global); // expected-error {{passing address of non-local object to __autoreleasing parameter for write-back}}
+
+  extern __strong id *test14_global_ptr;
+  test14_consume(test14_global_ptr); // expected-error {{passing address of non-local object to __autoreleasing parameter for write-back}}
+
+  static id static_local;
+  test14_consume(&static_local); // expected-error {{passing address of non-local object to __autoreleasing parameter for write-back}}
+
+  __weak id* wip;
+  test14_nowriteback(&static_local); // okay, not a write-back.
+  test14_nowriteback(wip); // expected-error{{passing '__weak id *' to parameter of type '__autoreleasing id const *' changes retain/release properties of pointer}}
+}
+
+void test15() {
+  __block __autoreleasing id x; // expected-error {{__block variables cannot have __autoreleasing lifetime}}
+}
+
+struct Test16;
+ at interface Test16a
+- (void) test16_0: (int) x;
+- (int) test16_1: (int) x; // expected-note {{one possibility}}
+- (int) test16_2: (int) x; // expected-note {{one possibility}}
+- (id) test16_3: (int) x __attribute__((ns_returns_retained)); // expected-note {{one possibility}}
+- (void) test16_4: (int) x __attribute__((ns_consumes_self)); // expected-note {{one possibility}}
+- (void) test16_5: (id) __attribute__((ns_consumed)) x; // expected-note {{one possibility}}
+- (void) test16_6: (id) x;
+ at end
+
+ at interface Test16b 
+- (void) test16_0: (int) x;
+- (int) test16_1: (char*) x; // expected-note {{also found}}
+- (char*) test16_2: (int) x; // expected-note {{also found}}
+- (id) test16_3: (int) x; // expected-note {{also found}}
+- (void) test16_4: (int) x; // expected-note {{also found}}
+- (void) test16_5: (id) x; // expected-note {{also found}}
+- (void) test16_6: (struct Test16 *) x;
+ at end
+
+void test16(void) {
+  id v;
+  [v test16_0: 0];
+  [v test16_1: 0]; // expected-error {{multiple methods named 'test16_1:' found with mismatched result, parameter type or attributes}}
+  [v test16_2: 0]; // expected-error {{multiple methods named}}
+  [v test16_3: 0]; // expected-error {{multiple methods named}}
+  [v test16_4: 0]; // expected-error {{multiple methods named}}
+  [v test16_5: 0]; // expected-error {{multiple methods named}}
+  [v test16_6: 0];
+}
+
+ at class Test17;
+ at protocol Test17p
+- (void) test17;
++ (void) test17;
+ at end
+void test17(void) {
+  Test17 *v0;
+  [v0 test17]; // expected-error {{receiver type 'Test17' for instance message is a forward declaration}}
+
+  Test17<Test17p> *v1;
+  [v1 test17]; // expected-error {{receiver type 'Test17<Test17p>' for instance message is a forward declaration}}
+
+  [Test17 test17]; // expected-error {{receiver 'Test17' for class message is a forward declaration}}
+}
+
+void test18(void) {
+  id x;
+  [x test18]; // expected-error {{no known instance method for selector 'test18'}}
+}
+
+extern struct Test19 *test19a;
+struct Test19 *const test19b = 0;
+void test19(void) {
+  id x;
+  x = (id) test19a; // expected-error {{bridged cast}} \
+  // expected-note{{use __bridge to convert directly (no change in ownership))}} \
+  // expected-note{{use __bridge_transfer to transfer ownership of a +1 'struct Test19 *' into ARC}}
+  x = (id) test19b; // expected-error {{bridged cast}} \
+  // expected-note{{use __bridge to convert directly (no change in ownership)}} \
+  // expected-note{{use __bridge_transfer to transfer ownership of a +1 'struct Test19 *' into ARC}}
+}
+
+// rdar://problem/8951453
+static __thread id test20_implicit; // expected-error {{thread-local variable has non-trivial lifetime: type is '__strong id'}}
+static __thread __strong id test20_strong; // expected-error {{thread-local variable has non-trivial lifetime: type is '__strong id'}}
+static __thread __weak id test20_weak; // expected-error {{thread-local variable has non-trivial lifetime: type is '__weak id'}}
+static __thread __autoreleasing id test20_autoreleasing; // expected-error {{thread-local variable has non-trivial lifetime: type is '__autoreleasing id'}} expected-error {{global variables cannot have __autoreleasing lifetime}}
+static __thread __unsafe_unretained id test20_unsafe;
+void test20(void) {
+  static __thread id test20_implicit; // expected-error {{thread-local variable has non-trivial lifetime: type is '__strong id'}}
+  static __thread __strong id test20_strong; // expected-error {{thread-local variable has non-trivial lifetime: type is '__strong id'}}
+  static __thread __weak id test20_weak; // expected-error {{thread-local variable has non-trivial lifetime: type is '__weak id'}}
+  static __thread __autoreleasing id test20_autoreleasing; // expected-error {{thread-local variable has non-trivial lifetime: type is '__autoreleasing id'}} expected-error {{global variables cannot have __autoreleasing lifetime}}
+  static __thread __unsafe_unretained id test20_unsafe;
+}
+
+// rdar://9310049
+_Bool fn(id obj) {
+    return (_Bool)obj;
+}
+
+// Check casting w/ lifetime qualifiers.
+void test21() {
+  __strong id *sip;
+  (void)(__weak id *)sip; // expected-error{{casting '__strong id *' to type '__weak id *' changes retain/release properties of pointer}}
+  (void)(__weak const id *)sip; // expected-error{{casting '__strong id *' to type '__weak id const *' changes retain/release properties of pointer}}
+  (void)(__autoreleasing id *)sip; // expected-error{{casting '__strong id *' to type '__autoreleasing id *' changes retain/release properties of pointer}}
+  (void)(__autoreleasing const id *)sip; // okay
+}
+
+// rdar://problem/9340462
+void test22(id x[]) { // expected-error {{must explicitly describe intended lifetime of an object array parameter}}
+}
+
+// rdar://problem/9400219
+void test23(void) {
+  void *ptr;
+  ptr = @"foo";
+  ptr = (ptr ? @"foo" : 0);
+  ptr = (ptr ? @"foo" : @"bar");
+}
+
+id test24(void) {
+  extern void test24_helper(void);
+  return test24_helper(), (void*) 0;
+}
+
+// rdar://9400841
+ at interface Base
+ at property (assign) id content;
+ at end
+
+ at interface Foo : Base
+-(void)test;
+ at end
+
+ at implementation Foo
+-(void)test {
+	super.content = 0;
+}
+ at end
+
+// <rdar://problem/9398437>
+void test25(Class *classes) {
+  Class *other_classes;
+  test25(other_classes);
+}
+
+void test26(id y) {
+  extern id test26_var1;
+  __sync_swap(&test26_var1, 0, y); // expected-error {{cannot perform atomic operation on a pointer to type '__strong id': type has non-trivial lifetime}}
+
+  extern __unsafe_unretained id test26_var2;
+  __sync_swap(&test26_var2, 0, y);
+}
+
+ at interface Test26
+- (id) init;
+- (id) initWithInt: (int) x;
+ at end
+ at implementation Test26
+- (id) init { return self; }
+- (id) initWithInt: (int) x {
+  [self init]; // expected-error {{the result of a delegate init call must be immediately returned or assigned to 'self'}}
+  return self;
+}
+ at end
+
+// rdar://9525555
+ at interface  Test27
+ at property id x; // expected-error {{ARC forbids properties of Objective-C objects with unspecified storage attribute}}
+ at property int y;
+ at end
+
+// rdar://9569264
+ at interface Test28
+ at property (nonatomic, assign) __strong id a; // expected-error {{unsafe_unretained property 'a' may not also be declared __strong}}
+ at end
+
+ at interface Test28 ()
+ at property (nonatomic, assign) __strong id b; // expected-error {{unsafe_unretained property 'b' may not also be declared __strong}}
+ at end
+
+ at implementation Test28
+ at synthesize a;
+ at synthesize b;
+ at end
+
+// rdar://9573962
+typedef struct Bark Bark;
+ at interface Test29
+ at property Bark* P;
+ at end
+
+ at implementation Test29
+ at synthesize P;
+- (id)Meth { 
+  Bark** f = &P; 
+  return 0; 
+}
+ at end
+
+// rdar://9495837
+ at interface Test30
+- (id) new;
+- (void)Meth;
+ at end
+
+ at implementation Test30
+- (id) new { return 0; }
+- (void) Meth {
+  __weak id x = [Test30 new]; // expected-warning {{cannot assign retained object to weak variable}}
+  id __unsafe_unretained u = [Test30 new]; // expected-warning {{cannot assign retained object to unsafe_unretained variable}}
+  id y = [Test30 new];
+  x = [Test30 new]; // expected-warning {{cannot assign retained object to weak variable}}
+  u = [Test30 new]; // expected-warning {{cannot assign retained object to unsafe_unretained variable}}
+  y = [Test30 new];
+}
+ at end
+
+// rdar://9411838
+ at protocol PTest31 @end
+
+int Test31() {
+    Class cls;
+    id ids;
+    id<PTest31> pids;
+    Class<PTest31> pcls;
+
+    int i =  (ids->isa ? 1 : 0); // expected-error {{member reference base type 'id' is not a structure or union}}
+    int j = (pids->isa ? 1 : 0); // expected-error {{member reference base type 'id<PTest31>' is not a structure or union}}
+    int k = (pcls->isa ? i : j); // expected-error {{member reference base type 'Class<PTest31>' is not a structure or union}}
+    return cls->isa ? i : j; // expected-error {{member reference base type 'Class' is not a structure or union}}
+}

Added: cfe/trunk/test/SemaObjC/autoreleasepool.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/autoreleasepool.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/autoreleasepool.m (added)
+++ cfe/trunk/test/SemaObjC/autoreleasepool.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1  -fsyntax-only -verify %s
+
+void *objc_autoreleasepool_push();
+void autoreleasepool_pop(void*);
+
+ at interface AUTORP @end
+
+ at implementation AUTORP
+- (void) unregisterTask:(id) task {
+  goto L;	// expected-error {{goto into protected scope}}
+
+  @autoreleasepool { // expected-note {{jump bypasses auto release push of @autoreleasepool block}}
+        void *tmp = objc_autoreleasepool_push();
+        L:
+        autoreleasepool_pop(tmp);
+        @autoreleasepool {
+          return;
+        }
+  }
+}
+ at end
+

Modified: cfe/trunk/test/SemaObjC/class-unavail-warning.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/class-unavail-warning.m?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/class-unavail-warning.m (original)
+++ cfe/trunk/test/SemaObjC/class-unavail-warning.m Wed Jun 15 18:02:42 2011
@@ -2,7 +2,7 @@
 // rdar://9092208
 
 __attribute__((unavailable("not available")))
- at interface MyClass { // expected-note 5 {{function has been explicitly marked unavailable here}}
+ at interface MyClass { // expected-note 5 {{declaration has been explicitly marked unavailable here}}
 @public
     void *_test;
 }

Modified: cfe/trunk/test/SemaObjC/error-property-gc-attr.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/error-property-gc-attr.m?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/error-property-gc-attr.m (original)
+++ cfe/trunk/test/SemaObjC/error-property-gc-attr.m Wed Jun 15 18:02:42 2011
@@ -20,9 +20,9 @@
 
 @implementation INTF
 @synthesize pweak=IVAR;  // expected-error {{existing ivar 'IVAR' for __weak property 'pweak' must be __weak}}
- at synthesize NOT=II; // expected-error {{property 'NOT' must be declared __weak to match existing ivar 'II' with __weak attribute}}
+ at synthesize NOT=II; // expected-error {{existing ivar 'II' for strong property 'NOT' may not be __weak}}
 @synthesize WID;
 @synthesize ID;
- at synthesize AWEAK; // expected-error {{property 'AWEAK' must be declared __weak to match existing ivar 'AWEAK' with __weak attribute}}
+ at synthesize AWEAK; // expected-error {{existing ivar 'AWEAK' for strong property 'AWEAK' may not be __weak}}
 @synthesize WI;
 @end

Modified: cfe/trunk/test/SemaObjC/property-10.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/property-10.m?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/property-10.m (original)
+++ cfe/trunk/test/SemaObjC/property-10.m Wed Jun 15 18:02:42 2011
@@ -5,14 +5,24 @@
 @interface I0
 @property(readonly, readwrite) int p0; // expected-error {{property attributes 'readonly' and 'readwrite' are mutually exclusive}}
 
- at property(retain) int p1; // expected-error {{property with 'retain' attribute must be of object type}}
+ at property(retain) int p1; // expected-error {{property with 'retain (or strong)' attribute must be of object type}}
+ at property(strong) int s1; // expected-error {{property with 'retain (or strong)' attribute must be of object type}}
 
 @property(copy) int p2; // expected-error {{property with 'copy' attribute must be of object type}}
 
 @property(assign, copy) id p3_0; // expected-error {{property attributes 'assign' and 'copy' are mutually exclusive}} 
 @property(assign, retain) id p3_1; // expected-error {{property attributes 'assign' and 'retain' are mutually exclusive}} 
+ at property(assign, strong) id s3_1; // expected-error {{property attributes 'assign' and 'strong' are mutually exclusive}} 
 @property(copy, retain) id p3_2; // expected-error {{property attributes 'copy' and 'retain' are mutually exclusive}} 
+ at property(copy, strong) id s3_2; // expected-error {{property attributes 'copy' and 'strong' are mutually exclusive}} 
 @property(assign, copy, retain) id p3_3; // expected-error {{property attributes 'assign' and 'copy' are mutually exclusive}}, expected-error {{property attributes 'assign' and 'retain' are mutually exclusive}} 
+ at property(assign, copy, strong) id s3_3; // expected-error {{property attributes 'assign' and 'copy' are mutually exclusive}}, expected-error {{property attributes 'assign' and 'strong' are mutually exclusive}} 
+
+ at property(unsafe_unretained, copy) id p4_0; // expected-error {{property attributes 'unsafe_unretained' and 'copy' are mutually exclusive}} 
+ at property(unsafe_unretained, retain) id p4_1; // expected-error {{property attributes 'unsafe_unretained' and 'retain' are mutually exclusive}} 
+ at property(unsafe_unretained, strong) id s4_1; // expected-error {{property attributes 'unsafe_unretained' and 'strong' are mutually exclusive}} 
+ at property(unsafe_unretained, copy, retain) id p4_3; // expected-error {{property attributes 'unsafe_unretained' and 'copy' are mutually exclusive}}, expected-error {{property attributes 'unsafe_unretained' and 'retain' are mutually exclusive}} 
+ at property(unsafe_unretained, copy, strong) id s4_3; // expected-error {{property attributes 'unsafe_unretained' and 'copy' are mutually exclusive}}, expected-error {{property attributes 'unsafe_unretained' and 'strong' are mutually exclusive}} 
 
 @property id p4; // expected-warning {{no 'assign', 'retain', or 'copy' attribute is specified - 'assign' is assumed}}, expected-warning {{default property attribute 'assign' not appropriate for non-gc object}}
 
@@ -22,7 +32,8 @@
 @end
 
 @interface I0()
- at property (retain) int PROP;	// expected-error {{property with 'retain' attribute must be of object type}}
+ at property (retain) int PROP;	// expected-error {{property with 'retain (or strong)' attribute must be of object type}}
+ at property (strong) int SPROP;	// expected-error {{property with 'retain (or strong)' attribute must be of object type}}
 @property(nonatomic,copy) int (*PROP1)(); // expected-error {{property with 'copy' attribute must be of object type}}
+ at property(nonatomic,weak) int (*PROP2)(); // expected-error {{property with 'weak' attribute must be of object type}}
 @end
-

Modified: cfe/trunk/test/SemaObjC/special-dep-unavail-warning.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/special-dep-unavail-warning.m?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/special-dep-unavail-warning.m (original)
+++ cfe/trunk/test/SemaObjC/special-dep-unavail-warning.m Wed Jun 15 18:02:42 2011
@@ -3,24 +3,24 @@
 
 @interface B
 - (void) depInA;
-- (void) unavailMeth __attribute__((unavailable)); // expected-note {{function has been explicitly marked unavailable here}}
+- (void) unavailMeth __attribute__((unavailable)); // expected-note {{has been explicitly marked unavailable here}}
 - (void) depInA1 __attribute__((deprecated));
 - (void) unavailMeth1;
 - (void) depInA2 __attribute__((deprecated));
-- (void) unavailMeth2 __attribute__((unavailable)); // expected-note {{function has been explicitly marked unavailable here}}
+- (void) unavailMeth2 __attribute__((unavailable)); // expected-note {{has been explicitly marked unavailable here}}
 - (void) depunavailInA;
-- (void) depunavailInA1 __attribute__((deprecated)) __attribute__((unavailable)); // expected-note {{function has been explicitly marked unavailable here}}
+- (void) depunavailInA1 __attribute__((deprecated)) __attribute__((unavailable)); // expected-note {{has been explicitly marked unavailable here}}
 - (void)FuzzyMeth __attribute__((deprecated));
 - (void)FuzzyMeth1 __attribute__((unavailable));
 @end
 
 @interface A
-- (void) unavailMeth1 __attribute__((unavailable)); // expected-note {{function has been explicitly marked unavailable here}}
+- (void) unavailMeth1 __attribute__((unavailable)); // expected-note {{has been explicitly marked unavailable here}}
 - (void) depInA __attribute__((deprecated));
 - (void) depInA2 __attribute__((deprecated));
 - (void) depInA1;
 - (void) unavailMeth2 __attribute__((unavailable)); 
-- (void) depunavailInA __attribute__((deprecated)) __attribute__((unavailable)); // expected-note {{function has been explicitly marked unavailable here}}
+- (void) depunavailInA __attribute__((deprecated)) __attribute__((unavailable)); // expected-note {{has been explicitly marked unavailable here}}
 - (void) depunavailInA1;
 - (void)FuzzyMeth __attribute__((unavailable));
 - (void)FuzzyMeth1 __attribute__((deprecated));

Modified: cfe/trunk/test/SemaObjC/synthesized-ivar.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/synthesized-ivar.m?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/synthesized-ivar.m (original)
+++ cfe/trunk/test/SemaObjC/synthesized-ivar.m Wed Jun 15 18:02:42 2011
@@ -51,3 +51,11 @@
 }
 @end
 
+ at interface A
+ at property (weak) id testObjectWeakProperty; // expected-note {{declared here}}
+ at end
+
+ at implementation A
+// rdar://9605088
+ at synthesize testObjectWeakProperty; // expected-error {{@synthesize of 'weak' property is only allowed in ARC or GC mode}}
+ at end

Added: cfe/trunk/test/SemaObjC/warn-retain-cycle.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/warn-retain-cycle.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/warn-retain-cycle.m (added)
+++ cfe/trunk/test/SemaObjC/warn-retain-cycle.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,91 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-nonfragile-abi -fobjc-arc -fblocks -verify %s
+
+ at interface Test0
+- (void) setBlock: (void(^)(void)) block;
+- (void) addBlock: (void(^)(void)) block;
+- (void) actNow;
+ at end
+void test0(Test0 *x) {
+  [x setBlock: // expected-note {{block will be retained by the captured object}}
+       ^{ [x actNow]; }]; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}}
+  x.block = // expected-note {{block will be retained by the captured object}}
+       ^{ [x actNow]; }; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}}
+
+  [x addBlock: // expected-note {{block will be retained by the captured object}}
+       ^{ [x actNow]; }]; // expected-warning {{capturing 'x' strongly in this block is likely to lead to a retain cycle}}
+
+  // These actually don't cause retain cycles.
+  __weak Test0 *weakx = x;
+  [x addBlock: ^{ [weakx actNow]; }];
+  [x setBlock: ^{ [weakx actNow]; }];
+  x.block = ^{ [weakx actNow]; };
+
+  // These do cause retain cycles, but we're not clever enough to figure that out.
+  [weakx addBlock: ^{ [x actNow]; }];
+  [weakx setBlock: ^{ [x actNow]; }];
+  weakx.block = ^{ [x actNow]; };
+}
+
+ at interface BlockOwner
+ at property (retain) void (^strong)(void);
+ at end
+
+ at interface Test1 {
+ at public
+  BlockOwner *owner;
+};
+ at property (retain) BlockOwner *owner;
+ at property (assign) __strong BlockOwner *owner2; // expected-error {{unsafe_unretained property 'owner2' may not also be declared __strong}}
+ at property (assign) BlockOwner *owner3;
+ at end
+void test1(Test1 *x) {
+  x->owner.strong = ^{ (void) x; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
+  x.owner.strong = ^{ (void) x; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
+  x.owner2.strong = ^{ (void) x; };
+  x.owner3.strong = ^{ (void) x; };
+}
+
+ at implementation Test1 {
+  BlockOwner * __unsafe_unretained owner3ivar;
+  __weak BlockOwner *weakowner;
+}
+ at dynamic owner;
+ at dynamic owner2;
+ at synthesize owner3 = owner3ivar;
+
+- (id) init {
+  self.owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
+  self.owner2.strong = ^{ (void) owner; };
+
+  // TODO: should we warn here?  What's the story with this kind of mismatch?
+  self.owner3.strong = ^{ (void) owner; };
+
+  owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
+
+  owner.strong = ^{ ^{ (void) owner; }(); }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
+
+  owner.strong = ^{ (void) sizeof(self); // expected-note {{block will be retained by an object strongly retained by the captured object}}
+                    (void) owner; }; // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}}
+
+  weakowner.strong = ^{ (void) owner; };
+
+  return self;
+}
+- (void) foo {
+  owner.strong = ^{ (void) owner; }; // expected-warning {{retain cycle}} expected-note {{block will be retained by an object strongly retained by the captured object}}
+}
+ at end
+
+void test2_helper(id);
+ at interface Test2 {
+  void (^block)(void);
+  id x;
+}
+ at end
+ at implementation Test2
+- (void) test {
+  block = ^{ // expected-note {{block will be retained by an object strongly retained by the captured object}}
+    test2_helper(x); // expected-warning {{capturing 'self' strongly in this block is likely to lead to a retain cycle}}
+  };
+}
+ at end

Added: cfe/trunk/test/SemaObjC/weak-property.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/weak-property.m?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/weak-property.m (added)
+++ cfe/trunk/test/SemaObjC/weak-property.m Wed Jun 15 18:02:42 2011
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1  -fsyntax-only -fobjc-nonfragile-abi -fobjc-arc -verify %s
+// rdar://8899430
+
+ at interface WeakPropertyTest {
+    Class isa;
+    __weak id value;
+    id x;
+}
+ at property (weak) id value1;
+ at property __weak id value;
+ at property () __weak id value2;
+
+ at property (weak, assign) id v1;  // expected-error {{property attributes 'assign' and 'weak' are mutually exclusive}}
+ at property (weak, copy) id v2; // expected-error {{property attributes 'copy' and 'weak' are mutually exclusive}}
+ at property (weak, retain) id v3; // expected-error {{property attributes 'retain' and 'weak' are mutually exclusive}}
+ at property (weak, assign) id v4;  // expected-error {{property attributes 'assign' and 'weak' are mutually exclusive}}
+
+ at property () __weak id x; // expected-note {{property declared here}}
+ at end
+
+ at implementation WeakPropertyTest
+ at synthesize x;	// expected-error {{existing ivar 'x' for __weak property 'x' must be __weak}}
+ at dynamic value1, value, value2, v1,v2,v3,v4;
+ at end

Added: cfe/trunk/test/SemaObjCXX/Inputs/arc-system-header.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/Inputs/arc-system-header.h?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/Inputs/arc-system-header.h (added)
+++ cfe/trunk/test/SemaObjCXX/Inputs/arc-system-header.h Wed Jun 15 18:02:42 2011
@@ -0,0 +1,14 @@
+ at interface B
+ at end
+
+
+ at interface A {
+ at public
+  union {
+    struct {
+      B *b;
+    } a_b;
+    void *void_ptr;
+  } data;
+}
+ at end

Added: cfe/trunk/test/SemaObjCXX/arc-0x.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/arc-0x.mm?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/arc-0x.mm (added)
+++ cfe/trunk/test/SemaObjCXX/arc-0x.mm Wed Jun 15 18:02:42 2011
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -std=c++0x -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify -fblocks %s
+
+// "Move" semantics, trivial version.
+void move_it(__strong id &&from) {
+  id to = static_cast<__strong id&&>(from);
+}
+
+// Deduction with 'auto'.
+ at interface A
++ alloc;
+- init;
+ at end
+
+// Ensure that deduction works with lifetime qualifiers.
+void deduction(id obj) {
+  auto a = [[A alloc] init];
+  __strong A** aPtr = &a;
+
+  auto a2([[A alloc] init]);
+  __strong A** aPtr2 = &a2;
+
+  __strong id *idp = new auto(obj);
+
+  __strong id array[17];
+  for (auto x : array) {
+    __strong id *xPtr = &x;
+  }
+}

Added: cfe/trunk/test/SemaObjCXX/arc-bool-conversion.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/arc-bool-conversion.mm?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/arc-bool-conversion.mm (added)
+++ cfe/trunk/test/SemaObjCXX/arc-bool-conversion.mm Wed Jun 15 18:02:42 2011
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify -fblocks -triple x86_64-apple-darwin10.0.0 %s
+// rdar://9310049
+
+bool fn(id obj) {
+    return (bool)obj;
+}
+

Added: cfe/trunk/test/SemaObjCXX/arc-bridged-cast.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/arc-bridged-cast.mm?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/arc-bridged-cast.mm (added)
+++ cfe/trunk/test/SemaObjCXX/arc-bridged-cast.mm Wed Jun 15 18:02:42 2011
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -fblocks -verify %s
+
+typedef const void *CFTypeRef;
+typedef const struct __CFString *CFStringRef;
+
+ at interface NSString
+ at end
+
+CFTypeRef CFCreateSomething();
+CFStringRef CFCreateString();
+CFTypeRef CFGetSomething();
+CFStringRef CFGetString();
+
+id CreateSomething();
+NSString *CreateNSString();
+
+template<typename IdType, typename StringType, typename IntPtrType>
+void from_cf() {
+  id obj1 = (__bridge_transfer IdType)CFCreateSomething();
+  id obj2 = (__bridge_transfer StringType)CFCreateString();
+  (__bridge IntPtrType)CFCreateSomething(); // expected-error{{incompatible types casting 'CFTypeRef' (aka 'const void *') to 'int *' with a __bridge cast}}
+  id obj3 = (__bridge IdType)CFGetSomething();
+  id obj4 = (__bridge StringType)CFGetString();
+}
+
+template void from_cf<id, NSString*, int*>(); // expected-note{{in instantiation of function template specialization}}
+
+template<typename IdType, typename StringType>
+void to_cf(id obj) {
+  CFTypeRef cf1 = (__bridge_retained IdType)CreateSomething();
+  CFStringRef cf2 = (__bridge_retained StringType)CreateNSString();
+  CFTypeRef cf3 = (__bridge IdType)CreateSomething();
+  CFStringRef cf4 = (__bridge StringType)CreateNSString(); 
+}
+
+template void to_cf<CFTypeRef, CFStringRef>(id);

Added: cfe/trunk/test/SemaObjCXX/arc-libcxx.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/arc-libcxx.mm?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/arc-libcxx.mm (added)
+++ cfe/trunk/test/SemaObjCXX/arc-libcxx.mm Wed Jun 15 18:02:42 2011
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-arc-cxxlib=libc++ -fobjc-nonfragile-abi -verify %s
+
+ at interface A @end
+
+void f(__strong id &sir, __weak id &wir, __autoreleasing id &air,
+       __unsafe_unretained id &uir) {
+  __strong id *sip = std::addressof(sir);
+  __weak id *wip = std::addressof(wir);
+  __autoreleasing id *aip = std::addressof(air);
+  __unsafe_unretained id *uip = std::addressof(uir);
+}

Added: cfe/trunk/test/SemaObjCXX/arc-libstdcxx.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/arc-libstdcxx.mm?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/arc-libstdcxx.mm (added)
+++ cfe/trunk/test/SemaObjCXX/arc-libstdcxx.mm Wed Jun 15 18:02:42 2011
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-arc-cxxlib=libstdc++ -fobjc-nonfragile-abi -verify %s
+
+ at interface A @end
+
+int check0[std::__is_scalar<__strong id>::__value? -1 : 1];
+int check1[std::__is_scalar<__weak id>::__value? -1 : 1];
+int check2[std::__is_scalar<__autoreleasing id>::__value? -1 : 1];
+int check3[std::__is_scalar<__strong A*>::__value? -1 : 1];
+int check4[std::__is_scalar<__weak A*>::__value? -1 : 1];
+int check5[std::__is_scalar<__autoreleasing A*>::__value? -1 : 1];

Added: cfe/trunk/test/SemaObjCXX/arc-memfunc.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/arc-memfunc.mm?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/arc-memfunc.mm (added)
+++ cfe/trunk/test/SemaObjCXX/arc-memfunc.mm Wed Jun 15 18:02:42 2011
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify -fblocks %s
+
+struct X0 {
+  static id makeObject1() __attribute__((ns_returns_retained));
+  id makeObject2() __attribute__((ns_returns_retained));
+};
+
+void test_X0(X0 x0, X0 *x0p) {
+  X0::makeObject1();
+  x0.makeObject2();
+  x0p->makeObject2();
+  id (X0::*pmf)() __attribute__((ns_returns_retained)) = &X0::makeObject2;
+  (x0.*pmf)();
+  (x0p->*pmf)();
+}

Added: cfe/trunk/test/SemaObjCXX/arc-non-pod.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/arc-non-pod.mm?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/arc-non-pod.mm (added)
+++ cfe/trunk/test/SemaObjCXX/arc-non-pod.mm Wed Jun 15 18:02:42 2011
@@ -0,0 +1,115 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -Warc-abi -verify -fblocks -triple x86_64-apple-darwin10.0.0 %s
+
+// Classes that have an Objective-C object pointer.
+struct HasObjectMember0 { // expected-warning{{'HasObjectMember0' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
+  id x;
+};
+
+struct HasObjectMember1 { // expected-warning{{'HasObjectMember1' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
+  id x[3];
+};
+
+struct HasObjectMember2 { // expected-warning{{'HasObjectMember2' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
+  id x[3][2];
+};
+
+// Don't complain if the type has non-external linkage
+namespace {
+  struct HasObjectMember3 {
+    id x[3][2];
+  };
+}
+
+// Don't complain if the Objective-C pointer type was explicitly given
+// no lifetime.
+struct HasObjectMember3 { 
+  __unsafe_unretained id x[3][2];
+};
+
+struct HasBlockPointerMember0 { // expected-warning{{'HasBlockPointerMember0' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
+  int (^bp)(int);
+};
+
+struct HasBlockPointerMember1 { // expected-warning{{'HasBlockPointerMember1' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
+  int (^bp[2][3])(int);
+};
+
+struct NonPOD {
+  NonPOD(const NonPOD&);
+};
+
+struct HasObjectMemberAndNonPOD0 { // expected-warning{{'HasObjectMemberAndNonPOD0' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
+  // expected-warning{{'HasObjectMemberAndNonPOD0' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+  id x;
+  NonPOD np;
+};
+
+struct HasObjectMemberAndNonPOD1 { // expected-warning{{'HasObjectMemberAndNonPOD1' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
+  // expected-warning{{'HasObjectMemberAndNonPOD1' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+  NonPOD np;
+  id x[3];
+};
+
+struct HasObjectMemberAndNonPOD2 { // expected-warning{{'HasObjectMemberAndNonPOD2' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
+  // expected-warning{{'HasObjectMemberAndNonPOD2' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+  NonPOD np;
+  id x[3][2];
+};
+
+struct HasObjectMemberAndNonPOD3 {
+  HasObjectMemberAndNonPOD3 &operator=(const HasObjectMemberAndNonPOD3&);
+  ~HasObjectMemberAndNonPOD3();
+  NonPOD np;
+  id x[3][2];
+};
+
+struct HasBlockPointerMemberAndNonPOD0 { // expected-warning{{'HasBlockPointerMemberAndNonPOD0' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
+// expected-warning{{'HasBlockPointerMemberAndNonPOD0' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+  NonPOD np;
+  int (^bp)(int);
+};
+
+struct HasBlockPointerMemberAndNonPOD1 { // expected-warning{{'HasBlockPointerMemberAndNonPOD1' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
+// expected-warning{{'HasBlockPointerMemberAndNonPOD1' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+  NonPOD np;
+  int (^bp[2][3])(int);
+};
+
+int check_non_pod_objc_pointer0[__is_pod(id)? -1 : 1];
+int check_non_pod_objc_pointer1[__is_pod(__strong id)? -1 : 1];
+int check_non_pod_objc_pointer2[__is_pod(__unsafe_unretained id)? 1 : -1];
+int check_non_pod_objc_pointer3[__is_pod(id[2][3])? -1 : 1];
+int check_non_pod_objc_pointer4[__is_pod(__unsafe_unretained id[2][3])? 1 : -1];
+int check_non_pod_block0[__is_pod(int (^)(int))? -1 : 1];
+int check_non_pod_block1[__is_pod(int (^ __unsafe_unretained)(int))? 1 : -1];
+
+struct FlexibleArrayMember0 {
+  int length;
+  id array[]; // expected-error{{flexible array member 'array' of non-POD element type 'id __strong[]'}}
+};
+
+struct FlexibleArrayMember1 {
+  int length;
+  __unsafe_unretained id array[];
+};
+
+// It's okay to pass a retainable type through an ellipsis.
+void variadic(...);
+void test_variadic() {
+  variadic(1, 17, @"Foo");
+}
+
+// It's okay to create a VLA of retainable types.
+void vla(int n) {
+  id vla[n];
+}
+
+ at interface Crufty {
+  union {
+    struct {
+      id object; // expected-note{{has __strong lifetime}}
+    } an_object; // expected-error{{union member 'an_object' has a non-trivial copy constructor}}
+    void *ptr;
+  } storage;
+}
+ at end

Added: cfe/trunk/test/SemaObjCXX/arc-object-init-destroy.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/arc-object-init-destroy.mm?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/arc-object-init-destroy.mm (added)
+++ cfe/trunk/test/SemaObjCXX/arc-object-init-destroy.mm Wed Jun 15 18:02:42 2011
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify -Warc-abi -fblocks -triple x86_64-apple-darwin10.0.0 %s
+
+typedef __strong id strong_id;
+typedef __weak id weak_id;
+void test_pseudo_destructors(__strong id *sptr, __weak id *wptr) {
+  sptr->~id(); // okay
+  wptr->~id(); // okay
+  sptr->~strong_id(); // okay
+  wptr->~weak_id();
+  sptr->~weak_id(); // expected-error{{pseudo-destructor destroys object of type '__strong id' with inconsistently-qualified type 'weak_id' (aka '__weak id')}}
+  wptr->strong_id::~strong_id(); // expected-error{{pseudo-destructor destroys object of type '__weak id' with inconsistently-qualified type 'strong_id' (aka '__strong id')}}
+  
+  sptr->id::~id(); // okay
+  wptr->id::~id(); // okay
+}
+
+void test_delete(__strong id *sptr, __weak id *wptr) {
+  delete sptr;
+  delete wptr;
+  delete [] sptr; // expected-warning{{destroying an array of '__strong id'; this array must not have been allocated from non-ARC code}}
+  delete [] wptr; // expected-warning{{destroying an array of '__weak id'; this array must not have been allocated from non-ARC code}}
+}
+
+void test_new(int n) {
+  (void)new strong_id;
+  (void)new weak_id;
+  (void)new strong_id [n]; // expected-warning{{allocating an array of 'strong_id' (aka '__strong id'); this array must not be deleted in non-ARC code}}
+  (void)new weak_id [n]; // expected-warning{{allocating an array of 'weak_id' (aka '__weak id'); this array must not be deleted in non-ARC code}}
+
+  (void)new __strong id;
+  (void)new __weak id;
+  (void)new __strong id [n]; // expected-warning{{allocating an array of '__strong id'; this array must not be deleted in non-ARC code}}
+
+  // Infer '__strong'.
+  __strong id *idptr = new id;
+  __strong id *idptr2 = new id [n]; // expected-warning{{allocating an array of '__strong id'; this array must not be deleted in non-ARC code}}
+
+  // ... but not for arrays.
+  typedef id id_array[2][3];
+  (void)new id_array; // expected-error{{'new' cannot allocate an array of 'id' with no explicit lifetime}}
+
+  typedef __strong id strong_id_array[2][3];
+  typedef __strong id strong_id_3[3];
+  strong_id_3 *idptr3 = new strong_id_array; // expected-warning{{allocating an array of '__strong id'; this array must not be deleted in non-ARC code}}
+}
+
+void test_jump_scope() {
+  goto done; // expected-error{{goto into protected scope}}
+  __strong id x; // expected-note{{jump bypasses initialization of retaining variable}}
+ done:
+  return;
+}

Added: cfe/trunk/test/SemaObjCXX/arc-overloading.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/arc-overloading.mm?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/arc-overloading.mm (added)
+++ cfe/trunk/test/SemaObjCXX/arc-overloading.mm Wed Jun 15 18:02:42 2011
@@ -0,0 +1,175 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify -fblocks %s
+
+// Simple lifetime conversions + diagnostics.
+int &f0(id __strong const *); // expected-note{{candidate function not viable: 1st argument ('__weak id *') has __weak lifetime, but parameter has __strong lifetime}}
+
+void test_f0() {
+  id __strong *sip;
+  id __strong const *csip;
+  id __weak *wip;
+  id __autoreleasing *aip;
+  id __unsafe_unretained *uip;
+
+  int &ir1 = f0(sip);
+  int &ir2 = f0(csip);
+  int &ir3 = f0(aip);
+  int &ir4 = f0(uip);
+  f0(wip); // expected-error{{no matching function for call to 'f0'}}
+}
+
+// Simple overloading
+int &f1(id __strong const *);
+float &f1(id __weak const *);
+
+void test_f1() {
+  id __strong *sip;
+  id __strong const *csip;
+  id __weak *wip;
+  id __autoreleasing *aip;
+  id __unsafe_unretained *uip;
+
+  int &ir1 = f1(sip);
+  int &ir2 = f1(csip);
+  float &fr1 = f1(wip);
+  int &ir3 = f1(aip);
+  int &ir4 = f1(uip);
+}
+
+// Simple overloading
+int &f2(id __strong const *); // expected-note{{candidate function}}
+float &f2(id __autoreleasing const *); // expected-note{{candidate function}}
+
+void test_f2() {
+  id __strong *sip;
+  id __strong const *csip;
+  id __weak *wip;
+  id __autoreleasing *aip;
+  id __unsafe_unretained *uip;
+
+  // Prefer non-lifetime conversions to lifetime conversions.
+  int &ir1 = f2(sip);
+  int &ir2 = f2(csip);
+  float &fr1 = f2(aip);
+
+  f2(uip); // expected-error{{call to 'f2' is ambiguous}}
+}
+
+// Writeback conversion
+int &f3(id __autoreleasing *); // expected-note{{candidate function not viable: 1st argument ('__unsafe_unretained id *') has __unsafe_unretained lifetime, but parameter has __autoreleasing lifetime}}
+
+void test_f3() {
+  id __strong *sip;
+  id __weak *wip;
+  id __autoreleasing *aip;
+  id __unsafe_unretained *uip;
+
+  int &ir1 = f3(sip);
+  int &ir2 = f3(wip);
+  int &ir3 = f3(aip);
+  f3(uip); // expected-error{{no matching function for call to 'f3'}}
+}
+
+// Writeback conversion vs. no conversion
+int &f4(id __autoreleasing *);
+float &f4(id __strong *);
+
+void test_f4() {
+  id __strong *sip;
+  id __weak *wip;
+  id __autoreleasing *aip;
+  extern __weak id *weak_global_ptr;
+
+  float &fr1 = f4(sip);
+  int &ir1 = f4(wip);
+  int &ir2 = f4(aip);
+  int &ir3 = f4(weak_global_ptr); // expected-error{{passing address of non-local object to __autoreleasing parameter for write-back}}
+}
+
+// Writeback conversion vs. other conversion.
+int &f5(id __autoreleasing *);
+float &f5(id const __unsafe_unretained *);
+
+void test_f5() {
+  id __strong *sip;
+  id __weak *wip;
+  id __autoreleasing *aip;
+
+  int &ir1 = f5(wip);
+  float &fr1 = f5(sip);
+  int &ir2 = f5(aip);
+}
+
+ at interface A
+ at end
+
+int &f6(id __autoreleasing *);
+float &f6(id const __unsafe_unretained *);
+
+void test_f6() {
+  A* __strong *sip;
+  A* __weak *wip;
+  A* __autoreleasing *aip;
+
+  int &ir1 = f6(wip);
+  float &fr1 = f6(sip);
+  int &ir2 = f6(aip);
+}
+
+// Reference binding
+void f7(__strong id&); // expected-note{{candidate function not viable: 1st argument ('__weak id') has __weak lifetime, but parameter has __strong lifetime}} \
+ // expected-note{{candidate function not viable: 1st argument ('__autoreleasing id') has __autoreleasing lifetime, but parameter has __strong lifetime}} \
+ // expected-note{{candidate function not viable: 1st argument ('__unsafe_unretained id') has __unsafe_unretained lifetime, but parameter has __strong lifetime}}
+
+void test_f7() {
+  __strong id strong_id;
+  __weak id weak_id;
+  __autoreleasing id autoreleasing_id;
+  __unsafe_unretained id unsafe_id;
+  f7(strong_id);
+  f7(weak_id); // expected-error{{no matching function for call to 'f7'}}
+  f7(autoreleasing_id); // expected-error{{no matching function for call to 'f7'}}
+  f7(unsafe_id); // expected-error{{no matching function for call to 'f7'}}
+}
+
+void f8(const __strong id&);
+
+void test_f8() {
+  __strong id strong_id;
+  __weak id weak_id;
+  __autoreleasing id autoreleasing_id;
+  __unsafe_unretained id unsafe_id;
+
+  f8(strong_id);
+  f8(weak_id);
+  f8(autoreleasing_id);
+  f8(unsafe_id);
+}
+
+int &f9(__strong id&);
+float &f9(const __autoreleasing id&);
+
+void test_f9() {
+  __strong id strong_id;
+  __weak id weak_id;
+  __autoreleasing id autoreleasing_id;
+  __unsafe_unretained id unsafe_id;
+
+  int &ir1 = f9(strong_id);
+  float &fr1 = f9(autoreleasing_id);
+  float &fr2 = f9(unsafe_id);
+  float &fr2a = f9(weak_id);
+
+  __strong A *strong_a;
+  __weak A *weak_a;
+  __autoreleasing A *autoreleasing_a;
+  __unsafe_unretained A *unsafe_unretained_a;
+  float &fr3 = f9(strong_a);
+  float &fr4 = f9(autoreleasing_a);
+  float &fr5 = f9(unsafe_unretained_a);
+  float &fr6 = f9(weak_a);
+
+  const __autoreleasing id& ar1 = strong_a;
+  const __autoreleasing id& ar2 = autoreleasing_a;
+  const __autoreleasing id& ar3 = unsafe_unretained_a;
+  const __autoreleasing id& ar4 = weak_a;
+}

Added: cfe/trunk/test/SemaObjCXX/arc-system-header.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/arc-system-header.mm?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/arc-system-header.mm (added)
+++ cfe/trunk/test/SemaObjCXX/arc-system-header.mm Wed Jun 15 18:02:42 2011
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fobjc-arc -fobjc-nonfragile-abi -isystem %S/Inputs %s -verify
+
+#include <arc-system-header.h>
+
+void f(A* a) {
+  a->data.void_ptr = 0;
+  a->data.a_b.b = 0; // expected-error{{'a_b' is unavailable: this system field has retaining lifetime}}
+}
+// Silly location below
+// expected-note{{declaration has been explicitly marked unavailable here}}

Added: cfe/trunk/test/SemaObjCXX/arc-templates.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/arc-templates.mm?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/arc-templates.mm (added)
+++ cfe/trunk/test/SemaObjCXX/arc-templates.mm Wed Jun 15 18:02:42 2011
@@ -0,0 +1,219 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify -fblocks %s
+
+ at interface A
+ at end
+
+template<typename T, typename U>
+struct is_same {
+  static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T> {
+  static const bool value = true;
+};
+
+// Instantiation for reference/pointer types that will get lifetime
+// adjustments.
+template<typename T>
+struct X0 {
+  typedef T* pointer; // expected-error{{pointer to non-const type 'id' with no explicit lifetime}} \
+  // expected-error{{pointer to non-const type 'A *' with no explicit lifetime}}
+  typedef T& reference; // expected-error{{reference to non-const type 'id' with no explicit lifetime}} \
+  // expected-error{{reference to non-const type 'A *' with no explicit lifetime}}
+};
+
+void test_X0() {
+  X0<id> x0id; // expected-note{{in instantiation of template class 'X0<id>' requested here}}
+  X0<A*> x0a; // expected-note{{in instantiation of template class 'X0<A *>' requested here}}
+  X0<__strong A*> x0sa;
+
+  id __strong *ptr;
+  id __strong val;
+  X0<__strong id>::pointer &ptr_ref = ptr;
+  X0<__strong id>::reference ref = val;
+}
+
+// Check template argument deduction (e.g., for specialization) using
+// lifetime qualifiers.
+template<typename T>
+struct is_pointer_strong {
+  static const bool value = false;
+};
+
+template<typename T>
+struct is_pointer_strong<__strong T*> {
+  static const bool value = true;
+};
+
+int check_ptr_strong1[is_pointer_strong<__strong id*>::value? 1 : -1];
+int check_ptr_strong2[is_pointer_strong<__weak id*>::value? -1 : 1];
+int check_ptr_strong3[is_pointer_strong<__autoreleasing id*>::value? -1 : 1];
+int check_ptr_strong4[is_pointer_strong<__unsafe_unretained id*>::value? -1 : 1];
+int check_ptr_strong5[is_pointer_strong<id>::value? -1 : 1];
+
+// Check substitution into lifetime-qualified dependent types.
+template<typename T>
+struct make_strong_pointer {
+  typedef __strong T *type;
+};
+
+// Adding qualifiers
+int check_make_strong1[is_same<make_strong_pointer<id>::type, __strong id *>::value ? 1 : -1];
+int check_make_strong2[is_same<make_strong_pointer<A*>::type, A* __strong *>::value ? 1 : -1];
+
+// Adding redundant qualifiers
+int check_make_strong3[is_same<make_strong_pointer<__strong id>::type, __strong id *>::value ? 1 : -1];
+int check_make_strong4[is_same<make_strong_pointer<__strong A*>::type, A* __strong *>::value ? 1 : -1];
+
+// Adding nonsensical qualifiers.
+int check_make_strong5[is_same<make_strong_pointer<int>::type, int *>::value ? 1 : -1];
+int check_make_strong6[is_same<make_strong_pointer<__weak id>::type, __weak id *>::value ? 1 : -1];
+
+// Check template argument deduction from function templates.
+template<typename T> struct identity { };
+
+template<typename T> identity<T> accept_strong_ptr(__strong T*);
+template<typename T> identity<T> accept_strong_ref(__strong T&);
+
+template<typename T> identity<T> accept_any_ptr(T*);
+template<typename T> identity<T> accept_any_ref(T&);
+
+void test_func_deduction_id() {
+  __strong id *sip;
+  __weak id *wip;
+  __autoreleasing id *aip;
+  __unsafe_unretained id *uip;
+
+  identity<id> res1 = accept_strong_ptr(sip);
+  identity<__strong id> res2 = accept_any_ptr(sip);
+
+  __strong id si;
+  __weak id wi;
+  __autoreleasing id ai;
+  __unsafe_unretained id ui;
+  identity<id> res3 = accept_strong_ref(si);
+  identity<__strong id> res4 = accept_any_ref(si);
+  identity<__weak id> res5 = accept_any_ref(wi);
+  identity<__autoreleasing id> res6 = accept_any_ref(ai);
+  identity<__unsafe_unretained id> res7 = accept_any_ref(ui);
+}
+
+void test_func_deduction_A() {
+  __strong A * *sip;
+  __weak A * *wip;
+  __autoreleasing A * *aip;
+  __unsafe_unretained A * *uip;
+
+  identity<A *> res1 = accept_strong_ptr(sip);
+  identity<__strong A *> res2 = accept_any_ptr(sip);
+
+  __strong A * si;
+  __weak A * wi;
+  __autoreleasing A * ai;
+  __unsafe_unretained A * ui;
+  identity<A *> res3 = accept_strong_ref(si);
+  identity<__strong A *> res4 = accept_any_ref(si);
+  identity<__weak A *> res5 = accept_any_ref(wi);
+  identity<__autoreleasing A *> res6 = accept_any_ref(ai);
+  identity<__unsafe_unretained A *> res7 = accept_any_ref(ui);
+}
+
+// Test partial ordering (qualified vs. non-qualified).
+template<typename T>
+struct classify_pointer_pointer {
+  static const unsigned value = 0;
+};
+
+template<typename T>
+struct classify_pointer_pointer<T*> {
+  static const unsigned value = 1;
+};
+
+template<typename T>
+struct classify_pointer_pointer<__strong T*> {
+  static const unsigned value = 2;
+};
+
+template<typename T>
+struct classify_pointer_pointer<__weak T*> {
+  static const unsigned value = 3;
+};
+
+template<typename T>
+struct classify_pointer_pointer<T&> {
+  static const unsigned value = 4;
+};
+
+template<typename T>
+struct classify_pointer_pointer<__strong T&> {
+  static const unsigned value = 5;
+};
+
+template<typename T>
+struct classify_pointer_pointer<__weak T&> {
+  static const unsigned value = 6;
+};
+
+int classify_ptr1[classify_pointer_pointer<int>::value == 0? 1 : -1];
+int classify_ptr2[classify_pointer_pointer<int *>::value == 1? 1 : -1];
+int classify_ptr3[classify_pointer_pointer<id __strong *>::value == 2? 1 : -1];
+int classify_ptr4[classify_pointer_pointer<id __weak *>::value == 3? 1 : -1];
+int classify_ptr5[classify_pointer_pointer<int&>::value == 4? 1 : -1];
+int classify_ptr6[classify_pointer_pointer<id __strong&>::value == 5? 1 : -1];
+int classify_ptr7[classify_pointer_pointer<id __weak&>::value == 6? 1 : -1];
+int classify_ptr8[classify_pointer_pointer<id __autoreleasing&>::value == 4? 1 : -1];
+int classify_ptr9[classify_pointer_pointer<id __unsafe_unretained&>::value == 4? 1 : -1];
+int classify_ptr10[classify_pointer_pointer<id __autoreleasing *>::value == 1? 1 : -1];
+int classify_ptr11[classify_pointer_pointer<id __unsafe_unretained *>::value == 1? 1 : -1];
+int classify_ptr12[classify_pointer_pointer<int *>::value == 1? 1 : -1];
+int classify_ptr13[classify_pointer_pointer<A * __strong *>::value == 2? 1 : -1];
+int classify_ptr14[classify_pointer_pointer<A * __weak *>::value == 3? 1 : -1];
+int classify_ptr15[classify_pointer_pointer<int&>::value == 4? 1 : -1];
+int classify_ptr16[classify_pointer_pointer<A * __strong&>::value == 5? 1 : -1];
+int classify_ptr17[classify_pointer_pointer<A * __weak&>::value == 6? 1 : -1];
+int classify_ptr18[classify_pointer_pointer<A * __autoreleasing&>::value == 4? 1 : -1];
+int classify_ptr19[classify_pointer_pointer<A * __unsafe_unretained&>::value == 4? 1 : -1];
+int classify_ptr20[classify_pointer_pointer<A * __autoreleasing *>::value == 1? 1 : -1];
+int classify_ptr21[classify_pointer_pointer<A * __unsafe_unretained *>::value == 1? 1 : -1];
+
+template<typename T> int& qual_vs_unqual_ptr(__strong T*);
+template<typename T> double& qual_vs_unqual_ptr(__weak T*);
+template<typename T> float& qual_vs_unqual_ptr(T*);
+template<typename T> int& qual_vs_unqual_ref(__strong T&);
+template<typename T> double& qual_vs_unqual_ref(__weak T&);
+template<typename T> float& qual_vs_unqual_ref(T&);
+
+void test_qual_vs_unqual_id() {
+  __strong id *sip;
+  __weak id *wip;
+  __autoreleasing id *aip;
+  __unsafe_unretained id *uip;
+
+  int &ir1 = qual_vs_unqual_ptr(sip);
+  double &dr1 = qual_vs_unqual_ptr(wip);
+  float &fr1 = qual_vs_unqual_ptr(aip);
+  float &fr2 = qual_vs_unqual_ptr(uip);
+
+  int &ir2 = qual_vs_unqual_ref(*sip);
+  double &dr2 = qual_vs_unqual_ref(*wip);
+  float &fr3 = qual_vs_unqual_ref(*aip);
+  float &fr4 = qual_vs_unqual_ref(*uip);
+}
+
+void test_qual_vs_unqual_a() {
+  __strong A * *sap;
+  __weak A * *wap;
+  __autoreleasing A * *aap;
+  __unsafe_unretained A * *uap;
+
+  int &ir1 = qual_vs_unqual_ptr(sap);
+  double &dr1 = qual_vs_unqual_ptr(wap);
+  float &fr1 = qual_vs_unqual_ptr(aap);
+  float &fr2 = qual_vs_unqual_ptr(uap);
+
+  int &ir2 = qual_vs_unqual_ref(*sap);
+  double &dr2 = qual_vs_unqual_ref(*wap);
+  float &fr3 = qual_vs_unqual_ref(*aap);
+  float &fr4 = qual_vs_unqual_ref(*uap);
+}

Added: cfe/trunk/test/SemaObjCXX/arc-type-conversion.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/arc-type-conversion.mm?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/arc-type-conversion.mm (added)
+++ cfe/trunk/test/SemaObjCXX/arc-type-conversion.mm Wed Jun 15 18:02:42 2011
@@ -0,0 +1,198 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -verify -fblocks %s
+// rdar://8843600
+
+void * cvt(id arg) // expected-note{{candidate function not viable: cannot convert argument of incomplete type 'void *' to '__strong id'}}
+{
+  void* voidp_val;
+  (void)(int*)arg; // expected-error {{cast of an Objective-C pointer to 'int *' is disallowed with ARC}}
+  (void)(id)arg;
+  (void)(__autoreleasing id*)arg; // expected-error{{C-style cast from 'id' to '__autoreleasing id *' casts away qualifiers}}
+  (void)(id*)arg; // expected-error {{pointer to non-const type 'id' with no explicit lifetime}} \
+  // expected-error{{C-style cast from 'id' to '__autoreleasing id *' casts away qualifiers}}
+
+  (void)(__autoreleasing id**)voidp_val;
+  (void)(void*)voidp_val;
+  (void)(void**)arg; // expected-error {{cast of an Objective-C pointer to 'void **' is disallowed}}
+  cvt((void*)arg); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'void *' requires a bridged cast}} \
+                   // expected-error {{no matching function for call to 'cvt'}} \
+  // expected-note{{use __bridge to convert directly (no change in ownership)}} \
+  // expected-note{{use __bridge_retained to make an ARC object available as a +1 'void *'}}
+  cvt(0);
+  (void)(__strong id**)(0);
+
+  // FIXME: Diagnostic could be better here.
+  return arg; // expected-error{{cannot initialize return object of type 'void *' with an lvalue of type '__strong id'}}
+}
+
+// rdar://8898937
+namespace rdar8898937 {
+
+typedef void (^dispatch_block_t)(void);
+
+void dispatch_once(dispatch_block_t block);
+static void _dispatch_once(dispatch_block_t block)
+{
+  dispatch_once(block);
+}
+
+}
+
+void static_casts(id arg) {
+  void* voidp_val;
+  (void)static_cast<int*>(arg); // expected-error {{cannot cast from type 'id' to pointer type 'int *'}}
+  (void)static_cast<id>(arg);
+  (void)static_cast<__autoreleasing id*>(arg); // expected-error{{cannot cast from type 'id' to pointer type '__autoreleasing id *'}}
+  (void)static_cast<id*>(arg); // expected-error {{cannot cast from type 'id' to pointer type '__autoreleasing id *'}} \
+  // expected-error{{pointer to non-const type 'id' with no explicit lifetime}}
+
+  (void)static_cast<__autoreleasing id**>(voidp_val);
+  (void)static_cast<void*>(voidp_val);
+  (void)static_cast<void**>(arg); // expected-error {{cannot cast from type 'id' to pointer type 'void **'}}
+  (void)static_cast<__strong id**>(0);  
+
+  __strong id *idp;
+  (void)static_cast<__autoreleasing id*>(idp); // expected-error{{static_cast from '__strong id *' to '__autoreleasing id *' is not allowed}}
+  (void)static_cast<__weak id*>(idp); // expected-error{{static_cast from '__strong id *' to '__weak id *' is not allowed}}
+}
+
+void test_const_cast(__strong id *sip, __weak id *wip, 
+                     const __strong id *csip, __weak const id *cwip) {
+  // Cannot use const_cast to cast between lifetime qualifications or
+  // add/remove lifetime qualifications.
+  (void)const_cast<__strong id *>(wip); // expected-error{{is not allowed}}
+  (void)const_cast<__weak id *>(sip); // expected-error{{is not allowed}}
+
+  // It's acceptable to cast away constness.
+  (void)const_cast<__strong id *>(csip);
+  (void)const_cast<__weak id *>(cwip);
+}
+
+void test_reinterpret_cast(__strong id *sip, __weak id *wip, 
+                           const __strong id *csip, __weak const id *cwip) {
+  // Okay to reinterpret_cast to add/remove/change lifetime
+  // qualifications.
+  (void)reinterpret_cast<__strong id *>(wip);
+  (void)reinterpret_cast<__weak id *>(sip);
+
+  // Not allowed to cast away constness
+  (void)reinterpret_cast<__strong id *>(csip); // expected-error{{reinterpret_cast from '__strong id const *' to '__strong id *' casts away qualifiers}}
+  (void)reinterpret_cast<__weak id *>(cwip); // expected-error{{reinterpret_cast from '__weak id const *' to '__weak id *' casts away qualifiers}}
+  (void)reinterpret_cast<__weak id *>(csip); // expected-error{{reinterpret_cast from '__strong id const *' to '__weak id *' casts away qualifiers}}
+  (void)reinterpret_cast<__strong id *>(cwip); // expected-error{{reinterpret_cast from '__weak id const *' to '__strong id *' casts away qualifiers}}
+}
+
+void test_cstyle_cast(__strong id *sip, __weak id *wip, 
+                      const __strong id *csip, __weak const id *cwip) {
+  // C-style casts aren't allowed to change Objective-C lifetime
+  // qualifiers (beyond what the normal implicit conversion allows).
+
+  (void)(__strong id *)wip; // expected-error{{C-style cast from '__weak id *' to '__strong id *' casts away qualifiers}}
+  (void)(__strong id *)cwip; // expected-error{{C-style cast from '__weak id const *' to '__strong id *' casts away qualifiers}}
+  (void)(__weak id *)sip; // expected-error{{C-style cast from '__strong id *' to '__weak id *' casts away qualifiers}}
+  (void)(__weak id *)csip; // expected-error{{C-style cast from '__strong id const *' to '__weak id *' casts away qualifiers}}
+
+  (void)(__strong const id *)wip; // expected-error{{C-style cast from '__weak id *' to '__strong id const *' casts away qualifiers}}
+  (void)(__strong const id *)cwip; // expected-error{{C-style cast from '__weak id const *' to '__strong id const *' casts away qualifiers}}
+  (void)(__weak const id *)sip; // expected-error{{C-style cast from '__strong id *' to '__weak id const *' casts away qualifiers}}
+  (void)(__weak const id *)csip; // expected-error{{C-style cast from '__strong id const *' to '__weak id const *' casts away qualifiers}}
+  (void)(__autoreleasing const id *)wip; // expected-error{{C-style cast from '__weak id *' to '__autoreleasing id const *' casts away qualifiers}}
+  (void)(__autoreleasing const id *)cwip; // expected-error{{C-style cast from '__weak id const *' to '__autoreleasing id const *' casts away qualifiers}}
+  (void)(__autoreleasing const id *)sip;
+  (void)(__autoreleasing const id *)csip;
+}
+
+void test_functional_cast(__strong id *sip, __weak id *wip,
+                          __autoreleasing id *aip) {
+  // Functional casts aren't allowed to change Objective-C lifetime
+  // qualifiers (beyond what the normal implicit conversion allows).
+
+  typedef __strong id *strong_id_pointer;
+  typedef __weak id *weak_id_pointer;
+  typedef __autoreleasing id *autoreleasing_id_pointer;
+
+  typedef const __strong id *const_strong_id_pointer;
+  typedef const __weak id *const_weak_id_pointer;
+  typedef const __autoreleasing id *const_autoreleasing_id_pointer;
+
+  (void)strong_id_pointer(wip); // expected-error{{functional-style cast from '__weak id *' to 'strong_id_pointer' (aka '__strong id *') casts away qualifiers}}
+  (void)weak_id_pointer(sip); // expected-error{{functional-style cast from '__strong id *' to 'weak_id_pointer' (aka '__weak id *') casts away qualifiers}}
+  (void)autoreleasing_id_pointer(sip); // expected-error{{functional-style cast from '__strong id *' to 'autoreleasing_id_pointer' (aka '__autoreleasing id *') casts away qualifiers}}
+  (void)autoreleasing_id_pointer(wip); // expected-error{{functional-style cast from '__weak id *' to 'autoreleasing_id_pointer' (aka '__autoreleasing id *') casts away qualifiers}}
+  (void)const_strong_id_pointer(wip); // expected-error{{functional-style cast from '__weak id *' to 'const_strong_id_pointer' (aka 'const __strong id *') casts away qualifiers}}
+  (void)const_weak_id_pointer(sip); // expected-error{{functional-style cast from '__strong id *' to 'const_weak_id_pointer' (aka 'const __weak id *') casts away qualifiers}}
+  (void)const_autoreleasing_id_pointer(sip);
+  (void)const_autoreleasing_id_pointer(aip);
+  (void)const_autoreleasing_id_pointer(wip); // expected-error{{functional-style cast from '__weak id *' to 'const_autoreleasing_id_pointer' (aka 'const __autoreleasing id *') casts away qualifiers}}
+}
+
+void test_unsafe_unretained(__strong id *sip, __weak id *wip,
+                            __autoreleasing id *aip,
+                            __unsafe_unretained id *uip,
+                            const __unsafe_unretained id *cuip) {
+  uip = sip; // expected-error{{assigning to '__unsafe_unretained id *' from incompatible type '__strong id *'}}
+  uip = wip; // expected-error{{assigning to '__unsafe_unretained id *' from incompatible type '__weak id *'}}
+  uip = aip; // expected-error{{assigning to '__unsafe_unretained id *' from incompatible type '__autoreleasing id *'}}
+
+  cuip = sip;
+  cuip = wip; // expected-error{{assigning to '__unsafe_unretained id const *' from incompatible type '__weak id *'}}
+  cuip = aip;
+}
+
+void to_void(__strong id *sip, __weak id *wip,
+             __autoreleasing id *aip,
+             __unsafe_unretained id *uip) {
+  void *vp1 = sip;
+  void *vp2 = wip;
+  void *vp3 = aip;
+  void *vp4 = uip;
+  (void)(void*)sip;
+  (void)(void*)wip;
+  (void)(void*)aip;
+  (void)(void*)uip;
+  (void)static_cast<void*>(sip);
+  (void)static_cast<void*>(wip);
+  (void)static_cast<void*>(aip);
+  (void)static_cast<void*>(uip);
+  (void)reinterpret_cast<void*>(sip);
+  (void)reinterpret_cast<void*>(wip);
+  (void)reinterpret_cast<void*>(aip);
+  (void)reinterpret_cast<void*>(uip);
+
+  (void)(void*)&sip;
+  (void)(void*)&wip;
+  (void)(void*)&aip;
+  (void)(void*)&uip;
+  (void)static_cast<void*>(&sip);
+  (void)static_cast<void*>(&wip);
+  (void)static_cast<void*>(&aip);
+  (void)static_cast<void*>(&uip);
+  (void)reinterpret_cast<void*>(&sip);
+  (void)reinterpret_cast<void*>(&wip);
+  (void)reinterpret_cast<void*>(&aip);
+  (void)reinterpret_cast<void*>(&uip);
+}
+
+void from_void(void *vp) {
+  __strong id *sip = (__strong id *)vp;
+  __weak id *wip = (__weak id *)vp;
+  __autoreleasing id *aip = (__autoreleasing id *)vp;
+  __unsafe_unretained id *uip = (__unsafe_unretained id *)vp;
+  __strong id *sip2 = static_cast<__strong id *>(vp);
+  __weak id *wip2 = static_cast<__weak id *>(vp);
+  __autoreleasing id *aip2 = static_cast<__autoreleasing id *>(vp);
+  __unsafe_unretained id *uip2 = static_cast<__unsafe_unretained id *>(vp);
+  __strong id *sip3 = reinterpret_cast<__strong id *>(vp);
+  __weak id *wip3 = reinterpret_cast<__weak id *>(vp);
+  __autoreleasing id *aip3 = reinterpret_cast<__autoreleasing id *>(vp);
+  __unsafe_unretained id *uip3 = reinterpret_cast<__unsafe_unretained id *>(vp);
+
+  __strong id **sipp = (__strong id **)vp;
+  __weak id **wipp = (__weak id **)vp;
+  __autoreleasing id **aipp = (__autoreleasing id **)vp;
+  __unsafe_unretained id **uipp = (__unsafe_unretained id **)vp;
+
+  sip = vp; // expected-error{{assigning to '__strong id *' from incompatible type 'void *'}}
+  wip = vp; // expected-error{{assigning to '__weak id *' from incompatible type 'void *'}}
+  aip = vp; // expected-error{{assigning to '__autoreleasing id *' from incompatible type 'void *'}}
+  uip = vp; // expected-error{{assigning to '__unsafe_unretained id *' from incompatible type 'void *'}}
+}

Added: cfe/trunk/test/SemaObjCXX/arc-type-traits.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/arc-type-traits.mm?rev=133103&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/arc-type-traits.mm (added)
+++ cfe/trunk/test/SemaObjCXX/arc-type-traits.mm Wed Jun 15 18:02:42 2011
@@ -0,0 +1,90 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-nonfragile-abi -verify %s
+
+// Check the results of the various type-trait query functions on
+// lifetime-qualified types in ARC.
+
+#define JOIN3(X,Y) X ## Y
+#define JOIN2(X,Y) JOIN3(X,Y)
+#define JOIN(X,Y) JOIN2(X,Y)
+
+#define TRAIT_IS_TRUE(Trait, Type) char JOIN2(Trait,__LINE__)[Trait(Type)? 1 : -1]
+#define TRAIT_IS_FALSE(Trait, Type) char JOIN2(Trait,__LINE__)[Trait(Type)? -1 : 1]
+  
+// __has_nothrow_assign
+TRAIT_IS_TRUE(__has_nothrow_assign, __strong id);
+TRAIT_IS_TRUE(__has_nothrow_assign, __weak id);
+TRAIT_IS_TRUE(__has_nothrow_assign, __autoreleasing id);
+TRAIT_IS_TRUE(__has_nothrow_assign, __unsafe_unretained id);
+
+// __has_nothrow_copy
+TRAIT_IS_TRUE(__has_nothrow_copy, __strong id);
+TRAIT_IS_TRUE(__has_nothrow_copy, __weak id);
+TRAIT_IS_TRUE(__has_nothrow_copy, __autoreleasing id);
+TRAIT_IS_TRUE(__has_nothrow_copy, __unsafe_unretained id);
+
+// __has_nothrow_constructor
+TRAIT_IS_TRUE(__has_nothrow_constructor, __strong id);
+TRAIT_IS_TRUE(__has_nothrow_constructor, __weak id);
+TRAIT_IS_TRUE(__has_nothrow_constructor, __autoreleasing id);
+TRAIT_IS_TRUE(__has_nothrow_constructor, __unsafe_unretained id);
+
+// __has_trivial_assign
+TRAIT_IS_FALSE(__has_trivial_assign, __strong id);
+TRAIT_IS_FALSE(__has_trivial_assign, __weak id);
+TRAIT_IS_FALSE(__has_trivial_assign, __autoreleasing id);
+TRAIT_IS_TRUE(__has_trivial_assign, __unsafe_unretained id);
+
+// __has_trivial_copy
+TRAIT_IS_FALSE(__has_trivial_copy, __strong id);
+TRAIT_IS_FALSE(__has_trivial_copy, __weak id);
+TRAIT_IS_FALSE(__has_trivial_copy, __autoreleasing id);
+TRAIT_IS_TRUE(__has_trivial_copy, __unsafe_unretained id);
+
+// __has_trivial_constructor
+TRAIT_IS_FALSE(__has_trivial_constructor, __strong id);
+TRAIT_IS_FALSE(__has_trivial_constructor, __weak id);
+TRAIT_IS_FALSE(__has_trivial_constructor, __autoreleasing id);
+TRAIT_IS_TRUE(__has_trivial_constructor, __unsafe_unretained id);
+
+// __has_trivial_destructor
+TRAIT_IS_FALSE(__has_trivial_destructor, __strong id);
+TRAIT_IS_FALSE(__has_trivial_destructor, __weak id);
+TRAIT_IS_TRUE(__has_trivial_destructor, __autoreleasing id);
+TRAIT_IS_TRUE(__has_trivial_destructor, __unsafe_unretained id);
+
+// __is_literal
+TRAIT_IS_FALSE(__is_literal, __strong id);
+TRAIT_IS_FALSE(__is_literal, __weak id);
+TRAIT_IS_FALSE(__is_literal, __autoreleasing id);
+TRAIT_IS_FALSE(__is_literal, __unsafe_unretained id);
+
+// __is_literal_type
+TRAIT_IS_FALSE(__is_literal_type, __strong id);
+TRAIT_IS_FALSE(__is_literal_type, __weak id);
+TRAIT_IS_FALSE(__is_literal_type, __autoreleasing id);
+TRAIT_IS_FALSE(__is_literal_type, __unsafe_unretained id);
+
+// __is_pod
+TRAIT_IS_FALSE(__is_pod, __strong id);
+TRAIT_IS_FALSE(__is_pod, __weak id);
+TRAIT_IS_FALSE(__is_pod, __autoreleasing id);
+TRAIT_IS_TRUE(__is_pod, __unsafe_unretained id);
+
+// __is_trivial
+TRAIT_IS_FALSE(__is_trivial, __strong id);
+TRAIT_IS_FALSE(__is_trivial, __weak id);
+TRAIT_IS_FALSE(__is_trivial, __autoreleasing id);
+TRAIT_IS_TRUE(__is_trivial, __unsafe_unretained id);
+
+// __is_scalar
+TRAIT_IS_FALSE(__is_scalar, __strong id);
+TRAIT_IS_FALSE(__is_scalar, __weak id);
+TRAIT_IS_FALSE(__is_scalar, __autoreleasing id);
+TRAIT_IS_TRUE(__is_scalar, __unsafe_unretained id);
+
+// __is_standard_layout
+TRAIT_IS_TRUE(__is_standard_layout, __strong id);
+TRAIT_IS_TRUE(__is_standard_layout, __weak id);
+TRAIT_IS_TRUE(__is_standard_layout, __autoreleasing id);
+TRAIT_IS_TRUE(__is_standard_layout, __unsafe_unretained id);
+

Modified: cfe/trunk/tools/libclang/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndex.cpp (original)
+++ cfe/trunk/tools/libclang/CIndex.cpp Wed Jun 15 18:02:42 2011
@@ -2374,7 +2374,8 @@
 unsigned clang_defaultEditingTranslationUnitOptions() {
   return CXTranslationUnit_PrecompiledPreamble | 
          CXTranslationUnit_CacheCompletionResults |
-         CXTranslationUnit_CXXPrecompiledPreamble;
+         CXTranslationUnit_CXXPrecompiledPreamble |
+         CXTranslationUnit_CXXChainedPCH;
 }
   
 CXTranslationUnit
@@ -4797,6 +4798,7 @@
               llvm::StringSwitch<bool>(II->getName())
               .Case("readonly", true)
               .Case("assign", true)
+              .Case("unsafe_unretained", true)
               .Case("readwrite", true)
               .Case("retain", true)
               .Case("copy", true)
@@ -4804,6 +4806,8 @@
               .Case("atomic", true)
               .Case("getter", true)
               .Case("setter", true)
+              .Case("strong", true)
+              .Case("weak", true)
               .Default(false))
             Tokens[I].int_data[0] = CXToken_Keyword;
         }

Modified: cfe/trunk/tools/libclang/CXCursor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXCursor.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CXCursor.cpp (original)
+++ cfe/trunk/tools/libclang/CXCursor.cpp Wed Jun 15 18:02:42 2011
@@ -92,6 +92,7 @@
   case Stmt::ObjCAtFinallyStmtClass:    
   case Stmt::ObjCAtThrowStmtClass:      
   case Stmt::ObjCAtSynchronizedStmtClass: 
+  case Stmt::ObjCAutoreleasePoolStmtClass:    
   case Stmt::ObjCForCollectionStmtClass:
   case Stmt::CXXCatchStmtClass:
   case Stmt::CXXTryStmtClass:  
@@ -167,7 +168,9 @@
   case Stmt::ObjCEncodeExprClass:       
   case Stmt::ObjCSelectorExprClass:   
   case Stmt::ObjCProtocolExprClass:   
-  case Stmt::ObjCIsaExprClass:       
+  case Stmt::ObjCIsaExprClass:   
+  case Stmt::ObjCIndirectCopyRestoreExprClass:
+  case Stmt::ObjCBridgedCastExprClass:
   case Stmt::ShuffleVectorExprClass: 
   case Stmt::BlockExprClass:  
   case Stmt::OpaqueValueExprClass:

Modified: cfe/trunk/tools/libclang/CXType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXType.cpp?rev=133103&r1=133102&r2=133103&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CXType.cpp (original)
+++ cfe/trunk/tools/libclang/CXType.cpp Wed Jun 15 18:02:42 2011
@@ -366,7 +366,11 @@
   QualType T = GetQualType(X);
   if (!T.getTypePtrOrNull())
     return 0;
-  return T->isPODType() ? 1 : 0;
+  
+  CXTranslationUnit TU = GetTU(X);
+  ASTUnit *AU = static_cast<ASTUnit*>(TU->TUData);
+
+  return T.isPODType(AU->getASTContext()) ? 1 : 0;
 }
 
 CXString clang_getDeclObjCTypeEncoding(CXCursor C) {





More information about the cfe-commits mailing list