From f85e193739c953358c865005855253af4f68a497 Mon Sep 17 00:00:00 2001
From: John McCall
Date: Wed, 15 Jun 2011 23:02:42 +0000
Subject: [PATCH] Automatic Reference Counting.
Language-design credit goes to a lot of people, but I particularly want
to single out Blaine Garst and Patrick Beard for their contributions.
Compiler implementation credit goes to Argyrios, Doug, Fariborz, and myself,
in no particular order.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133103 91177308-0d34-0410-b5e6-96231b3b80d8
---
docs/LanguageExtensions.html | 7 +
include/clang/AST/ASTContext.h | 16 +-
include/clang/AST/CanonicalType.h | 2 +-
include/clang/AST/DeclObjC.h | 19 +-
include/clang/AST/Expr.h | 2 +
include/clang/AST/ExprObjC.h | 130 +-
include/clang/AST/OperationKinds.h | 25 +-
include/clang/AST/ParentMap.h | 1 +
include/clang/AST/PrettyPrinter.h | 6 +-
include/clang/AST/RecursiveASTVisitor.h | 5 +
include/clang/AST/Stmt.h | 8 +
include/clang/AST/StmtObjC.h | 33 +
include/clang/AST/Type.h | 238 ++-
include/clang/Basic/Attr.td | 5 +
include/clang/Basic/DiagnosticCommonKinds.td | 1 +
include/clang/Basic/DiagnosticDriverKinds.td | 4 +
.../clang/Basic/DiagnosticFrontendKinds.td | 3 +
include/clang/Basic/DiagnosticGroups.td | 2 +
include/clang/Basic/DiagnosticSemaKinds.td | 188 +-
include/clang/Basic/LangOptions.h | 6 +
include/clang/Basic/StmtNodes.td | 5 +
include/clang/Basic/TokenKinds.def | 6 +
include/clang/Driver/CC1Options.td | 15 +
include/clang/Driver/Options.td | 15 +
include/clang/Driver/ToolChain.h | 6 +-
include/clang/Frontend/CodeGenOptions.h | 2 +
include/clang/Frontend/FrontendOptions.h | 8 +
include/clang/Frontend/PreprocessorOptions.h | 17 +-
include/clang/Frontend/Utils.h | 1 +
include/clang/Parse/Parser.h | 4 +-
include/clang/Rewrite/Rewriter.h | 5 +-
include/clang/Sema/AttributeList.h | 3 +
include/clang/Sema/DeclSpec.h | 16 +-
include/clang/Sema/DelayedDiagnostic.h | 41 +-
include/clang/Sema/Initialization.h | 101 +-
include/clang/Sema/Overload.h | 18 +-
include/clang/Sema/Sema.h | 128 +-
include/clang/Serialization/ASTBitCodes.h | 12 +-
lib/AST/ASTContext.cpp | 52 +-
lib/AST/DeclCXX.cpp | 36 +-
lib/AST/DeclObjC.cpp | 24 +-
lib/AST/DeclPrinter.cpp | 5 +
lib/AST/Expr.cpp | 36 +-
lib/AST/ExprClassification.cpp | 2 +
lib/AST/ExprConstant.cpp | 19 +-
lib/AST/ItaniumMangle.cpp | 42 +-
lib/AST/ParentMap.cpp | 9 +
lib/AST/StmtPrinter.cpp | 17 +
lib/AST/StmtProfile.cpp | 15 +
lib/AST/Type.cpp | 407 ++++-
lib/AST/TypePrinter.cpp | 117 +-
lib/Analysis/ReachableCode.cpp | 6 +
lib/Basic/DiagnosticIDs.cpp | 5 +
lib/Basic/IdentifierTable.cpp | 7 +-
lib/Basic/Targets.cpp | 36 +-
lib/CodeGen/CGBlocks.cpp | 224 ++-
lib/CodeGen/CGBlocks.h | 2 +-
lib/CodeGen/CGCall.cpp | 274 ++-
lib/CodeGen/CGCall.h | 47 +-
lib/CodeGen/CGClass.cpp | 93 +-
lib/CodeGen/CGDebugInfo.cpp | 1 +
lib/CodeGen/CGDecl.cpp | 256 ++-
lib/CodeGen/CGDeclCXX.cpp | 27 +-
lib/CodeGen/CGException.cpp | 6 +-
lib/CodeGen/CGExpr.cpp | 216 ++-
lib/CodeGen/CGExprAgg.cpp | 24 +-
lib/CodeGen/CGExprCXX.cpp | 90 +-
lib/CodeGen/CGExprConstant.cpp | 2 +
lib/CodeGen/CGExprScalar.cpp | 57 +-
lib/CodeGen/CGObjC.cpp | 1379 ++++++++++++++-
lib/CodeGen/CGObjCGNU.cpp | 4 +-
lib/CodeGen/CGObjCMac.cpp | 129 +-
lib/CodeGen/CGObjCRuntime.h | 8 +-
lib/CodeGen/CGStmt.cpp | 5 +-
lib/CodeGen/CGValue.h | 28 +-
lib/CodeGen/CodeGenFunction.cpp | 19 +-
lib/CodeGen/CodeGenFunction.h | 83 +-
lib/CodeGen/CodeGenModule.cpp | 21 +-
lib/CodeGen/CodeGenModule.h | 87 +-
lib/CodeGen/ItaniumCXXABI.cpp | 35 +-
lib/CodeGen/TargetInfo.cpp | 6 +-
lib/CodeGen/TargetInfo.h | 14 +
lib/Driver/ToolChain.cpp | 9 +-
lib/Driver/ToolChains.cpp | 97 +-
lib/Driver/ToolChains.h | 18 +
lib/Driver/Tools.cpp | 44 +-
lib/Frontend/CompilerInvocation.cpp | 45 +-
lib/Frontend/InitPreprocessor.cpp | 145 +-
lib/Lex/PPMacroExpansion.cpp | 5 +
lib/Parse/ParseDecl.cpp | 4 +-
lib/Parse/ParseExpr.cpp | 32 +-
lib/Parse/ParseObjc.cpp | 42 +-
lib/Rewrite/FixItRewriter.cpp | 3 +-
lib/Rewrite/Rewriter.cpp | 73 +-
lib/Sema/AttributeList.cpp | 5 +
lib/Sema/DelayedDiagnostic.cpp | 3 +
lib/Sema/JumpDiagnostics.cpp | 144 +-
lib/Sema/Sema.cpp | 40 +-
lib/Sema/SemaCXXCast.cpp | 137 +-
lib/Sema/SemaChecking.cpp | 282 ++-
lib/Sema/SemaCodeComplete.cpp | 97 +-
lib/Sema/SemaDecl.cpp | 240 ++-
lib/Sema/SemaDeclAttr.cpp | 112 +-
lib/Sema/SemaDeclCXX.cpp | 45 +-
lib/Sema/SemaDeclObjC.cpp | 429 ++++-
lib/Sema/SemaExpr.cpp | 229 ++-
lib/Sema/SemaExprCXX.cpp | 308 +++-
lib/Sema/SemaExprObjC.cpp | 409 ++++-
lib/Sema/SemaInit.cpp | 315 +++-
lib/Sema/SemaObjCProperty.cpp | 383 ++++-
lib/Sema/SemaOverload.cpp | 298 +++-
lib/Sema/SemaStmt.cpp | 51 +-
lib/Sema/SemaTemplate.cpp | 15 +-
lib/Sema/SemaTemplateDeduction.cpp | 7 +
lib/Sema/SemaType.cpp | 313 +++-
lib/Sema/TreeTransform.h | 84 +-
lib/Sema/TypeLocBuilder.h | 9 +
lib/Serialization/ASTReader.cpp | 15 +-
lib/Serialization/ASTReaderStmt.cpp | 34 +-
lib/Serialization/ASTWriter.cpp | 3 +
lib/Serialization/ASTWriterStmt.cpp | 26 +
.../Checkers/DeadStoresChecker.cpp | 6 +-
.../Checkers/StackAddrEscapeChecker.cpp | 20 +-
lib/StaticAnalyzer/Core/CFRefCount.cpp | 107 +-
lib/StaticAnalyzer/Core/ExprEngine.cpp | 47 +-
test/Analysis/objc-arc.m | 149 ++
test/Analysis/pr4209.m | 6 +-
test/CodeGenObjC/arc-arm.m | 20 +
test/CodeGenObjC/arc-block-ivar-layout.m | 60 +
test/CodeGenObjC/arc-bridged-cast.m | 90 +
test/CodeGenObjC/arc-foreach.m | 27 +
test/CodeGenObjC/arc-ivar-layout.m | 44 +
test/CodeGenObjC/arc-no-runtime.m | 9 +
test/CodeGenObjC/arc-related-result-type.m | 30 +
test/CodeGenObjC/arc-unopt.m | 69 +
test/CodeGenObjC/arc-weak-property.m | 55 +
test/CodeGenObjC/arc.m | 1511 +++++++++++++++++
test/CodeGenObjC/autorelease.m | 30 +
test/CodeGenObjC/block-6.m | 14 +-
test/CodeGenObjC/mrr-autorelease.m | 24 +
test/CodeGenObjC/nonlazy-msgSend.m | 6 +
test/CodeGenObjC/related-result-type.m | 54 +
test/CodeGenObjCXX/arc-globals.mm | 27 +
test/CodeGenObjCXX/arc-mangle.mm | 25 +
test/CodeGenObjCXX/arc-new-delete.mm | 86 +
test/CodeGenObjCXX/arc-pseudo-destructors.mm | 21 +
test/CodeGenObjCXX/arc-references.mm | 53 +
.../arc-special-member-functions.mm | 154 ++
test/CodeGenObjCXX/arc.mm | 152 ++
test/CodeGenObjCXX/copy.mm | 26 +
test/Driver/arc-exceptions.m | 5 +
test/Driver/arc.c | 14 +
test/Driver/ios-simulator-arcruntime.c | 5 +
test/Driver/no-objc-arr.m | 8 +
test/Index/arc-annotate.m | 38 +
test/Index/arc-complete.m | 16 +
test/Index/complete-exprs.m | 9 +-
test/Index/complete-property-flags.m | 2 +
test/Lexer/has_feature_objc_arc.m | 20 +
test/PCH/Inputs/arc.h | 20 +
test/PCH/arc.m | 9 +
test/SemaObjC/Inputs/arc-system-header.h | 42 +
test/SemaObjC/arc-bridged-cast.m | 40 +
test/SemaObjC/arc-decls.m | 64 +
test/SemaObjC/arc-no-runtime.m | 15 +
test/SemaObjC/arc-non-pod-memaccess.m | 55 +
test/SemaObjC/arc-property-decl-attrs.m | 67 +
test/SemaObjC/arc-property-lifetime.m | 112 ++
test/SemaObjC/arc-property.m | 48 +
test/SemaObjC/arc-system-header.m | 48 +
test/SemaObjC/arc-type-conversion.m | 55 +
test/SemaObjC/arc-unsafe_unretained.m | 12 +
test/SemaObjC/arc.m | 550 ++++++
test/SemaObjC/autoreleasepool.m | 22 +
test/SemaObjC/class-unavail-warning.m | 2 +-
test/SemaObjC/error-property-gc-attr.m | 4 +-
test/SemaObjC/property-10.m | 17 +-
test/SemaObjC/special-dep-unavail-warning.m | 10 +-
test/SemaObjC/synthesized-ivar.m | 8 +
test/SemaObjC/warn-retain-cycle.m | 91 +
test/SemaObjC/weak-property.m | 24 +
test/SemaObjCXX/Inputs/arc-system-header.h | 14 +
test/SemaObjCXX/arc-0x.mm | 28 +
test/SemaObjCXX/arc-bool-conversion.mm | 7 +
test/SemaObjCXX/arc-bridged-cast.mm | 36 +
test/SemaObjCXX/arc-libcxx.mm | 11 +
test/SemaObjCXX/arc-libstdcxx.mm | 10 +
test/SemaObjCXX/arc-memfunc.mm | 15 +
test/SemaObjCXX/arc-non-pod.mm | 115 ++
test/SemaObjCXX/arc-object-init-destroy.mm | 52 +
test/SemaObjCXX/arc-overloading.mm | 175 ++
test/SemaObjCXX/arc-system-header.mm | 10 +
test/SemaObjCXX/arc-templates.mm | 219 +++
test/SemaObjCXX/arc-type-conversion.mm | 198 +++
test/SemaObjCXX/arc-type-traits.mm | 90 +
tools/libclang/CIndex.cpp | 6 +-
tools/libclang/CXCursor.cpp | 5 +-
tools/libclang/CXType.cpp | 6 +-
198 files changed, 13876 insertions(+), 1101 deletions(-)
create mode 100644 test/Analysis/objc-arc.m
create mode 100644 test/CodeGenObjC/arc-arm.m
create mode 100644 test/CodeGenObjC/arc-block-ivar-layout.m
create mode 100644 test/CodeGenObjC/arc-bridged-cast.m
create mode 100644 test/CodeGenObjC/arc-foreach.m
create mode 100644 test/CodeGenObjC/arc-ivar-layout.m
create mode 100644 test/CodeGenObjC/arc-no-runtime.m
create mode 100644 test/CodeGenObjC/arc-related-result-type.m
create mode 100644 test/CodeGenObjC/arc-unopt.m
create mode 100644 test/CodeGenObjC/arc-weak-property.m
create mode 100644 test/CodeGenObjC/arc.m
create mode 100644 test/CodeGenObjC/autorelease.m
create mode 100644 test/CodeGenObjC/mrr-autorelease.m
create mode 100644 test/CodeGenObjC/nonlazy-msgSend.m
create mode 100644 test/CodeGenObjC/related-result-type.m
create mode 100644 test/CodeGenObjCXX/arc-globals.mm
create mode 100644 test/CodeGenObjCXX/arc-mangle.mm
create mode 100644 test/CodeGenObjCXX/arc-new-delete.mm
create mode 100644 test/CodeGenObjCXX/arc-pseudo-destructors.mm
create mode 100644 test/CodeGenObjCXX/arc-references.mm
create mode 100644 test/CodeGenObjCXX/arc-special-member-functions.mm
create mode 100644 test/CodeGenObjCXX/arc.mm
create mode 100644 test/CodeGenObjCXX/copy.mm
create mode 100644 test/Driver/arc-exceptions.m
create mode 100644 test/Driver/arc.c
create mode 100644 test/Driver/ios-simulator-arcruntime.c
create mode 100644 test/Driver/no-objc-arr.m
create mode 100644 test/Index/arc-annotate.m
create mode 100644 test/Index/arc-complete.m
create mode 100644 test/Lexer/has_feature_objc_arc.m
create mode 100644 test/PCH/Inputs/arc.h
create mode 100644 test/PCH/arc.m
create mode 100644 test/SemaObjC/Inputs/arc-system-header.h
create mode 100644 test/SemaObjC/arc-bridged-cast.m
create mode 100644 test/SemaObjC/arc-decls.m
create mode 100644 test/SemaObjC/arc-no-runtime.m
create mode 100644 test/SemaObjC/arc-non-pod-memaccess.m
create mode 100644 test/SemaObjC/arc-property-decl-attrs.m
create mode 100644 test/SemaObjC/arc-property-lifetime.m
create mode 100644 test/SemaObjC/arc-property.m
create mode 100644 test/SemaObjC/arc-system-header.m
create mode 100644 test/SemaObjC/arc-type-conversion.m
create mode 100644 test/SemaObjC/arc-unsafe_unretained.m
create mode 100644 test/SemaObjC/arc.m
create mode 100644 test/SemaObjC/autoreleasepool.m
create mode 100644 test/SemaObjC/warn-retain-cycle.m
create mode 100644 test/SemaObjC/weak-property.m
create mode 100644 test/SemaObjCXX/Inputs/arc-system-header.h
create mode 100644 test/SemaObjCXX/arc-0x.mm
create mode 100644 test/SemaObjCXX/arc-bool-conversion.mm
create mode 100644 test/SemaObjCXX/arc-bridged-cast.mm
create mode 100644 test/SemaObjCXX/arc-libcxx.mm
create mode 100644 test/SemaObjCXX/arc-libstdcxx.mm
create mode 100644 test/SemaObjCXX/arc-memfunc.mm
create mode 100644 test/SemaObjCXX/arc-non-pod.mm
create mode 100644 test/SemaObjCXX/arc-object-init-destroy.mm
create mode 100644 test/SemaObjCXX/arc-overloading.mm
create mode 100644 test/SemaObjCXX/arc-system-header.mm
create mode 100644 test/SemaObjCXX/arc-templates.mm
create mode 100644 test/SemaObjCXX/arc-type-conversion.mm
create mode 100644 test/SemaObjCXX/arc-type-traits.mm
diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html
index 8f43725d82..cce2e8c5b0 100644
--- a/docs/LanguageExtensions.html
+++ b/docs/LanguageExtensions.html
@@ -65,6 +65,7 @@ td {
Objective-C Features
Function Overloading in C
@@ -669,6 +670,12 @@ property access via the given method. In all other respects, a method
with a related result type is treated the same way as method without a
related result type.
+
+Automatic reference counting
+
+
+Clang provides support for automated reference counting in Objective-C, which eliminates the need for manual retain/release/autorelease message sends. There are two feature macros associated with automatic reference counting: __has_feature(objc_arc)
indicates the availability of automated reference counting in general, while __has_feature(objc_arc_weak)
indicates that automated reference counting also includes support for __weak
pointers to Objective-C objects.
+
Function Overloading in C
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 517c25df24..468343d2a0 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -993,6 +993,18 @@ public:
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 @@ public:
/// 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
diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h
index 2518814904..38e6b41977 100644
--- a/include/clang/AST/CanonicalType.h
+++ b/include/clang/AST/CanonicalType.h
@@ -250,7 +250,6 @@ public:
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 @@ public:
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.
///
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index 74ceb43c71..2c12b837bd 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -1240,6 +1240,9 @@ class ObjCImplementationDecl : public ObjCImplDecl {
/// 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 @@ class ObjCImplementationDecl : public ObjCImplDecl {
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
/// 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;
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index ce86458ed4..df20cb4057 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -2276,6 +2276,8 @@ private:
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
diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h
index 8163923d62..472a7efcda 100644
--- a/include/clang/AST/ExprObjC.h
+++ b/include/clang/AST/ExprObjC.h
@@ -456,7 +456,11 @@ class ObjCMessageExpr : public Expr {
///
/// 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 @@ class ObjCMessageExpr : public Expr {
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 @@ public:
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 @@ public:
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(Operand); }
+ const Expr *getSubExpr() const { return cast(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(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
diff --git a/include/clang/AST/OperationKinds.h b/include/clang/AST/OperationKinds.h
index 35c72c45ce..004426e89a 100644
--- a/include/clang/AST/OperationKinds.h
+++ b/include/clang/AST/OperationKinds.h
@@ -245,7 +245,17 @@ enum CastKind {
/// \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 @@ enum UnaryOperatorKind {
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
diff --git a/include/clang/AST/ParentMap.h b/include/clang/AST/ParentMap.h
index 9ea5a0930d..22c1e7269f 100644
--- a/include/clang/AST/ParentMap.h
+++ b/include/clang/AST/ParentMap.h
@@ -32,6 +32,7 @@ public:
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(S));
diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h
index cf5fadbd18..fc8ac36b3b 100644
--- a/include/clang/AST/PrettyPrinter.h
+++ b/include/clang/AST/PrettyPrinter.h
@@ -41,7 +41,7 @@ struct PrintingPolicy {
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 @@ struct PrintingPolicy {
/// that entity (e.g., "enum "). Otherwise, just
/// prints "" for the name.
bool AnonymousTagLocations : 1;
+
+ /// \brief When true, suppress printing of the __strong lifetime qualifier in
+ /// ARC.
+ unsigned SuppressStrongLifetime : 1;
};
} // end namespace clang
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index a8f182a5bc..1a30df6d8b 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -1721,6 +1721,7 @@ DEF_TRAVERSE_STMT(ObjCAtSynchronizedStmt, { })
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(ObjCMessageExpr, { })
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, { })
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index 695fb0403e..2fe2a20e49 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -183,6 +183,13 @@ protected:
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 @@ protected:
DeclRefExprBitfields DeclRefExprBits;
CastExprBitfields CastExprBits;
CallExprBitfields CallExprBits;
+ ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits;
};
friend class ASTStmtReader;
diff --git a/include/clang/AST/StmtObjC.h b/include/clang/AST/StmtObjC.h
index 1800a71f91..d996fc5cad 100644
--- a/include/clang/AST/StmtObjC.h
+++ b/include/clang/AST/StmtObjC.h
@@ -342,6 +342,39 @@ public:
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
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 77633831ff..26632c37bd 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -126,6 +126,28 @@ public:
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 @@ public:
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 @@ public:
addAddressSpace(Q.getAddressSpace());
if (Q.hasObjCGCAttr())
addObjCGCAttr(Q.getObjCGCAttr());
+ if (Q.hasObjCLifetime())
+ addObjCLifetime(Q.getObjCLifetime());
}
}
@@ -287,6 +341,8 @@ public:
!hasAddressSpace() || !qs.hasAddressSpace());
assert(getObjCGCAttr() == qs.getObjCGCAttr() ||
!hasObjCGCAttr() || !qs.hasObjCGCAttr());
+ assert(getObjCLifetime() == qs.getObjCLifetime() ||
+ !hasObjCLifetime() || !qs.hasObjCLifetime());
Mask |= qs.Mask;
}
@@ -301,10 +357,30 @@ public:
// 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 @@ public:
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 @@ public:
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 @@ public:
/// 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 @@ public:
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 @@ public:
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 @@ public:
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 @@ protected:
/// 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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
}
CanQualType getCanonicalTypeUnqualified() const; // in CanonicalType.h
void dump() const;
+
static bool classof(const Type *) { return true; }
friend class ASTReader;
@@ -2340,30 +2456,33 @@ class FunctionType : public Type {
// * 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(Bits)) {}
+ ExtInfo(unsigned Bits) : Bits(static_cast(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 @@ class FunctionType : public Type {
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 @@ class FunctionType : public Type {
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 @@ public:
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 @@ public:
unsigned NumExceptions;
const QualType *Exceptions;
Expr *NoexceptExpr;
+ const bool *ConsumedArguments;
};
private:
@@ -2523,7 +2654,7 @@ private:
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 @@ private:
/// 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 @@ private:
/// 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(arg_type_end());
+ if (getExceptionSpecType() != EST_ComputedNoexcept)
+ eh_end += NumExceptions;
+ else
+ eh_end += 1; // NoexceptExpr
+
+ return reinterpret_cast(eh_end);
+ }
+
public:
unsigned getNumArgs() const { return NumArgs; }
QualType getArgType(unsigned i) const {
@@ -2562,6 +2713,8 @@ public:
} else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
EPI.NoexceptExpr = getNoexceptExpr();
}
+ if (hasAnyConsumedArgs())
+ EPI.ConsumedArguments = getConsumedArgsBuffer();
return EPI;
}
@@ -2647,6 +2800,16 @@ public:
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 @@ public:
// Enumerated operand (string or keyword).
attr_objc_gc,
+ attr_objc_lifetime,
attr_pcs,
FirstEnumOperandKind = attr_objc_gc,
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index e4c6722e83..dea67ab9f3 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -400,6 +400,11 @@ def ObjCNSObject : InheritableAttr {
let Spellings = ["NSObject"];
}
+def ObjCPreciseLifetime : Attr {
+ let Spellings = ["objc_precise_lifetime"];
+ let Subjects = [Var];
+}
+
def Overloadable : Attr {
let Spellings = ["overloadable"];
}
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index 50110fb537..4b5de366cb 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -32,6 +32,7 @@ def note_type_being_defined : Note<
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
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index 908a69b162..409c6a2016 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -82,6 +82,10 @@ def err_drv_conflicting_deployment_targets : Error<
"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">;
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index 4aa85134aa..120ba67dc1 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -137,6 +137,9 @@ def warn_pch_nonfragile_abi2 : Error<
"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">;
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 98706dd227..7444ca44ad 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -169,6 +169,8 @@ def ImplicitAtomic : DiagGroup<"implicit-atomic-properties">;
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">;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index ea736c0cd2..00d0e6fab2 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -430,6 +430,12 @@ def warn_objc_property_copy_missing_on_block : Warning<
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_bad_property_context : Error<
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_ivar_in_superclass_use : Error<
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 @@ def err_format_attribute_implicit_this_format_string : Error<
"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 @@ def err_as_qualified_auto_decl : Error<
"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_cconv_varargs : Error<
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 @@ def note_ovl_candidate_bad_gc : Note<"candidate "
"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 err_unavailable_message : Error<"%0 is unavailable: %1">;
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 @@ def note_protected_by_objc_finally : Note<
"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 @@ def note_exits_cxx_try : Note<
"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_empty_aggregate_gnu : Extension<
def ext_flexible_array_union_gnu : Extension<
"flexible array member %0 in a union is a GNU extension">, InGroup;
+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,
+ 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, 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, 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;
+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>;
+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>;
+
+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 @@ def err_typecheck_incompatible_address_space : Error<
"|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<
diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h
index 0557b41f51..7eda0aa3fd 100644
--- a/include/clang/Basic/LangOptions.h
+++ b/include/clang/Basic/LangOptions.h
@@ -130,6 +130,10 @@ public:
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 @@ public:
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;
diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td
index 03f4cc3ec6..f503950c20 100644
--- a/include/clang/Basic/StmtNodes.td
+++ b/include/clang/Basic/StmtNodes.td
@@ -37,6 +37,7 @@ def ObjCAtFinallyStmt : Stmt;
def ObjCAtThrowStmt : Stmt;
def ObjCAtSynchronizedStmt : Stmt;
def ObjCForCollectionStmt : Stmt;
+def ObjCAutoreleasePoolStmt : Stmt;
// C++ statments
def CXXCatchStmt : Stmt;
@@ -130,6 +131,10 @@ def ObjCProtocolExpr : DStmt;
def ObjCIvarRefExpr : DStmt;
def ObjCPropertyRefExpr : DStmt;
def ObjCIsaExpr : DStmt;
+def ObjCIndirectCopyRestoreExpr : DStmt;
+
+// Obj-C ARC Expressions.
+def ObjCBridgedCastExpr : DStmt;
// CUDA Expressions.
def CUDAKernelCallExpr : DStmt;
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index dfba7eec8a..dd105a169b 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -422,6 +422,11 @@ KEYWORD(__pascal , KEYALL)
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(try)
OBJC1_AT_KEYWORD(catch)
OBJC1_AT_KEYWORD(finally)
OBJC1_AT_KEYWORD(synchronized)
+OBJC1_AT_KEYWORD(autoreleasepool)
OBJC2_AT_KEYWORD(property)
OBJC2_AT_KEYWORD(package)
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index e4ec205817..cc594085ff 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -383,6 +383,13 @@ def create_module : Flag<"-create-module">,
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 @@ def fconstant_string_class : Separate<"-fconstant-string-class">,
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">,
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 23b351c78a..079f759514 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -112,6 +112,13 @@ def ccc_print_phases : Flag<"-ccc-print-phases">, CCCDebugOpt,
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, Flags<[Unsupported]>;
@@ -382,6 +389,10 @@ def fno_verbose_asm : Flag<"-fno-verbose-asm">, Group;
def fno_working_directory : Flag<"-fno-working-directory">, Group;
def fno_wrapv : Flag<"-fno-wrapv">, Group;
def fno_zero_initialized_in_bss : Flag<"-fno-zero-initialized-in-bss">, Group;
+def fobjc_arc : Flag<"-fobjc-arc">, Group;
+def fno_objc_arc : Flag<"-fno-objc-arc">, Group;
+def fobjc_arc_exceptions : Flag<"-fobjc-arc-exceptions">, Group;
+def fno_objc_arc_exceptions : Flag<"-fno-objc-arc-exceptions">, Group;
def fobjc_atdefs : Flag<"-fobjc-atdefs">, Group;
def fobjc_call_cxx_cdtors : Flag<"-fobjc-call-cxx-cdtors">, Group;
def fobjc_default_synthesize_properties :
@@ -392,6 +403,10 @@ def fobjc_gc_only : Flag<"-fobjc-gc-only">, Group;
def fobjc_gc : Flag<"-fobjc-gc">, Group;
def fobjc_legacy_dispatch : Flag<"-fobjc-legacy-dispatch">, Group;
def fobjc_new_property : Flag<"-fobjc-new-property">, Group;
+def fobjc_infer_related_result_type : Flag<"-fobjc-infer-related-result-type">,
+ Group;
+def fno_objc_infer_related_result_type : Flag<
+ "-fno-objc-infer-related-result-type">, Group;
// Objective-C ABI options.
def fobjc_abi_version_EQ : Joined<"-fobjc-abi-version=">, Group;
diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h
index 626d54c37b..053732a82f 100644
--- a/include/clang/Driver/ToolChain.h
+++ b/include/clang/Driver/ToolChain.h
@@ -166,6 +166,9 @@ public:
/// 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 @@ public:
/// 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.
diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h
index 1c686c76df..7736d7fd6a 100644
--- a/include/clang/Frontend/CodeGenOptions.h
+++ b/include/clang/Frontend/CodeGenOptions.h
@@ -36,6 +36,7 @@ public:
};
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:
public:
CodeGenOptions() {
AsmVerbose = 0;
+ ObjCAutoRefCountExceptions = 0;
CXAAtExit = 1;
CXXCtorDtorAliases = 0;
DataSections = 0;
diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
index 02f6f868fe..e97be26a64 100644
--- a/include/clang/Frontend/FrontendOptions.h
+++ b/include/clang/Frontend/FrontendOptions.h
@@ -77,6 +77,13 @@ public:
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 > Inputs;
@@ -131,6 +138,7 @@ public:
ShowStats = 0;
ShowTimers = 0;
ShowVersion = 0;
+ ARCMTAction = ARCMT_None;
}
/// getInputKindForExtension - Return the appropriate input kind for a file
diff --git a/include/clang/Frontend/PreprocessorOptions.h b/include/clang/Frontend/PreprocessorOptions.h
index e471c5cf1d..2f99aaa522 100644
--- a/include/clang/Frontend/PreprocessorOptions.h
+++ b/include/clang/Frontend/PreprocessorOptions.h
@@ -26,6 +26,15 @@ namespace clang {
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 @@ public:
/// 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 >::iterator
remapped_file_iterator;
typedef std::vector >::const_iterator
@@ -145,7 +159,8 @@ public:
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));
diff --git a/include/clang/Frontend/Utils.h b/include/clang/Frontend/Utils.h
index 3c34c2dce2..93d2c7d501 100644
--- a/include/clang/Frontend/Utils.h
+++ b/include/clang/Frontend/Utils.h
@@ -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;
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index e4cdc27c43..cb8df4c938 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -1375,6 +1375,7 @@ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl &Names,
StmtResult ParseObjCTryStmt(SourceLocation atLoc);
StmtResult ParseObjCThrowStmt(SourceLocation atLoc);
StmtResult ParseObjCSynchronizedStmt(SourceLocation atLoc);
+ StmtResult ParseObjCAutoreleasePoolStmt(SourceLocation atLoc);
//===--------------------------------------------------------------------===//
@@ -1616,7 +1617,8 @@ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl &Names,
TypeResult ParseTypeName(SourceRange *Range = 0,
Declarator::TheContext Context
- = Declarator::TypeNameContext);
+ = Declarator::TypeNameContext,
+ ObjCDeclSpec *objcQuals = 0);
void ParseBlockId();
void ProhibitAttributes(ParsedAttributesWithRange &attrs) {
diff --git a/include/clang/Rewrite/Rewriter.h b/include/clang/Rewrite/Rewriter.h
index 7861e99928..676744ada3 100644
--- a/include/clang/Rewrite/Rewriter.h
+++ b/include/clang/Rewrite/Rewriter.h
@@ -183,8 +183,11 @@ public:
/// 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
diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index 72cd47589f..a3122db3b3 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/include/clang/Sema/AttributeList.h
@@ -198,6 +198,7 @@ public:
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 @@ public:
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.
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index 7ce4e00943..e0faab9426 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -40,6 +40,7 @@ namespace clang {
class NamespaceDecl;
class NestedNameSpecifier;
class NestedNameSpecifierLoc;
+ class ObjCDeclSpec;
class Preprocessor;
class Declarator;
struct TemplateIdAnnotation;
@@ -344,6 +345,8 @@ private:
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 @@ public:
ProtocolQualifiers(0),
NumProtocolQualifiers(0),
ProtocolLocs(0),
- writtenBS() {
+ writtenBS(),
+ ObjCQualifiers(0) {
}
~DeclSpec() {
delete [] ProtocolQualifiers;
@@ -653,6 +657,9 @@ public:
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 @@ public:
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 @@ private:
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
};
diff --git a/include/clang/Sema/DelayedDiagnostic.h b/include/clang/Sema/DelayedDiagnostic.h
index 8395138ab6..8ab9382264 100644
--- a/include/clang/Sema/DelayedDiagnostic.h
+++ b/include/clang/Sema/DelayedDiagnostic.h
@@ -112,7 +112,7 @@ private:
/// 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 @@ public:
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(AccessData);
@@ -155,6 +169,25 @@ public:
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 @@ private:
size_t MessageLen;
} DeprecationData;
+ struct {
+ unsigned Diagnostic;
+ unsigned Argument;
+ void *OperandType;
+ } ForbiddenTypeData;
+
/// Access control.
char AccessData[sizeof(AccessedEntity)];
};
diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h
index 5dc4438671..7a5dbaca19 100644
--- a/include/clang/Sema/Initialization.h
+++ b/include/clang/Sema/Initialization.h
@@ -86,9 +86,13 @@ private:
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 @@ private:
: 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 @@ public:
/// \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());
+
+ InitializedEntity Entity;
+ Entity.Kind = EK_Parameter;
+ Entity.Type = Context.getVariableArrayDecayedType(
+ Parm->getType().getUnqualifiedType());
+ Entity.Parent = 0;
+ Entity.Parameter = (Consumed | reinterpret_cast(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 @@ public:
/// \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 @@ public:
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 @@ private:
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 @@ public:
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 @@ public:
/// \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 @@ public:
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 @@ public:
/// \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;
diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h
index 55931f2318..32d4cbdac1 100644
--- a/include/clang/Sema/Overload.h
+++ b/include/clang/Sema/Overload.h
@@ -77,6 +77,7 @@ namespace clang {
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 @@ namespace clang {
/// 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 @@ namespace clang {
/// (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 @@ namespace clang {
/// 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.
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 4ddc80a72d..2ec868a94d 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -108,6 +108,7 @@ namespace clang {
class ObjCInterfaceDecl;
class ObjCIvarDecl;
template class ObjCList;
+ class ObjCMessageExpr;
class ObjCMethodDecl;
class ObjCPropertyDecl;
class ObjCProtocolDecl;
@@ -247,6 +248,10 @@ public:
/// 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 @@ public:
/// \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 @@ public:
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 @@ public:
return FunctionScopes.back();
}
- bool hasAnyErrorsInThisFunction() const;
+ bool hasAnyUnrecoverableErrorsInThisFunction() const;
/// \brief Retrieve the current block, if any.
sema::BlockScopeInfo *getCurBlock();
@@ -838,7 +848,7 @@ public:
const FunctionProtoType *Source, SourceLocation SourceLoc);
TypeResult ActOnTypeName(Scope *S, Declarator &D);
-
+
bool RequireCompleteType(SourceLocation Loc, QualType T,
const PartialDiagnostic &PD,
std::pair Note);
@@ -1305,13 +1315,13 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
void HandleDelayedDeprecationCheck(sema::DelayedDiagnostic &DD, Decl *Ctx);
+ bool makeUnavailableInSystemHeader(SourceLocation loc,
+ llvm::StringRef message);
+
//===--------------------------------------------------------------------===//
// Expression Parsing Callbacks: SemaExpr.cpp.
@@ -2146,6 +2170,8 @@ public:
void PopExpressionEvaluationContext();
+ void DiscardCleanupsInEvaluationContext();
+
void MarkDeclarationReferenced(SourceLocation Loc, Decl *D);
void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T);
void MarkDeclarationsReferencedInExpr(Expr *E);
@@ -4982,6 +5008,15 @@ public:
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 @@ public:
const ObjCObjectPointerType *OPT,
bool IsInstance);
+ bool inferObjCARCLifetime(ValueDecl *decl);
+
ExprResult
HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
Expr *BaseExpr,
@@ -5098,6 +5135,22 @@ public:
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 @@ public:
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 @@ public:
/// 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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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);
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index c881b23ed1..12f701e460 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -922,6 +922,8 @@ namespace clang {
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 @@ namespace clang {
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 @@ namespace clang {
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
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 4c66ed8d7e..fac2eacc4f 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -221,9 +221,9 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
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 @@ ASTContext::getFunctionType(QualType ResultTy,
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 @@ ASTContext::getFunctionType(QualType ResultTy,
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 @@ CanQualType ASTContext::getCanonicalParamType(QualType T) const {
return CanQualType::CreateUnsafe(Result);
}
-
QualType ASTContext::getUnqualifiedArrayType(QualType type,
Qualifiers &quals) {
SplitQualType splitType = type.getSplitUnqualifiedType();
@@ -3725,11 +3730,7 @@ void ASTContext::setBlockDescriptorExtendedType(QualType T) {
}
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()) {
@@ -4826,20 +4827,6 @@ CanQualType ASTContext::getFromTargetType(unsigned Type) const {
// 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(Ty)) {
- if (TypedefNameDecl *TD = TDT->getDecl())
- if (TD->getAttr())
- return true;
- }
- return false;
-}
-
/// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's
/// garbage collection attribute.
///
@@ -5452,6 +5439,9 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
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 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
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 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
// 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
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 08ac2a5be4..c10e6c40d3 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -228,6 +228,11 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
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 @@ NotASpecialMember:;
// 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 @@ NotASpecialMember:;
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() {
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()) {
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index e2c4f38ff9..99eb0d386b 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -474,8 +474,28 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context,
} 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();
+
+ // '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"),
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 421770ea70..19554a3baa 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -933,6 +933,11 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
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;
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 987213907e..97f4ea6cba 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -1045,6 +1045,10 @@ const char *CastExpr::getCastKindName() const {
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 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
case ObjCMessageExprClass: {
const ObjCMessageExpr *ME = cast(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()) {
Loc = getExprLoc();
@@ -2519,7 +2534,7 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T,
/*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(Method? Method
: Sel.getAsOpaquePtr())),
SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc)
@@ -2540,7 +2555,8 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T,
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(Method? Method
: Sel.getAsOpaquePtr())),
SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc)
@@ -2571,7 +2587,8 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T,
: 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(Method? Method
: Sel.getAsOpaquePtr())),
SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc)
@@ -2702,6 +2719,19 @@ ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const {
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;
}
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index d177cb5cbc..1a1fa91a40 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -162,6 +162,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
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 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
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(E)->getTypeAsWritten());
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 06c5645afb..432ffee08d 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -282,6 +282,17 @@ public:
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 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_GetObjCProperty:
case CK_LValueBitCast:
case CK_UserDefinedConversion:
+ case CK_ObjCProduceObject:
+ case CK_ObjCConsumeObject:
return false;
case CK_LValueToRValue:
@@ -2301,6 +2314,8 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
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 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::PackExpansionExprClass:
case Expr::SubstNonTypeTemplateParmPackExprClass:
case Expr::AsTypeExprClass:
+ case Expr::ObjCIndirectCopyRestoreExprClass:
return ICEDiag(2, E->getLocStart());
case Expr::SizeOfPackExprClass:
@@ -2995,7 +3011,8 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::CXXFunctionalCastExprClass:
case Expr::CXXStaticCastExprClass:
case Expr::CXXReinterpretCastExprClass:
- case Expr::CXXConstCastExprClass: {
+ case Expr::CXXConstCastExprClass:
+ case Expr::ObjCBridgedCastExprClass: {
const Expr *SubExpr = cast(E)->getSubExpr();
if (SubExpr->getType()->isIntegralOrEnumerationType())
return CheckICE(SubExpr, Ctx);
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index e81ec7e54b..a77fe5f48a 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -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 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
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:
+ //
+ // ::= U "__strong"
+ // ::= U "__weak"
+ // ::= U "__autoreleasing"
+ // ::= 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 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
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 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
mangleExpression(cast(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(E)->getBridgeKindName();
+ Out << "v1U" << Kind.size() << Kind;
+ }
+ // Fall through to mangle the cast itself.
+
case Expr::CStyleCastExprClass:
case Expr::CXXStaticCastExprClass:
case Expr::CXXDynamicCastExprClass:
diff --git a/lib/AST/ParentMap.cpp b/lib/AST/ParentMap.cpp
index eca351aec8..b7b2005e9f 100644
--- a/lib/AST/ParentMap.cpp
+++ b/lib/AST/ParentMap.cpp
@@ -66,6 +66,15 @@ Stmt *ParentMap::getParentIgnoreParenCasts(Stmt *S) const {
return S;
}
+Stmt *ParentMap::getOuterParenParent(Stmt *S) const {
+ Stmt *Paren = 0;
+ while (isa(S)) {
+ Paren = S;
+ S = getParent(S);
+ };
+ return Paren;
+}
+
bool ParentMap::isConsumedExpr(Expr* E) const {
Stmt *P = getParent(E);
Stmt *DirectChild = E;
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 87588e4518..d6a67b13ef 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -449,6 +449,12 @@ void StmtPrinter::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *Node) {
OS << "\n";
}
+void StmtPrinter::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *Node) {
+ Indent() << "@autoreleasepool";
+ PrintRawCompoundStmt(dyn_cast(Node->getSubStmt()));
+ OS << "\n";
+}
+
void StmtPrinter::PrintRawCXXCatchStmt(CXXCatchStmt *Node) {
OS << "catch (";
if (Decl *ExDecl = Node->getExceptionDecl())
@@ -1464,6 +1470,17 @@ void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) {
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();
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index b117cd9a52..c70c87a724 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -220,6 +220,10 @@ void StmtProfiler::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) {
VisitStmt(S);
}
+void StmtProfiler::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
+ VisitStmt(S);
+}
+
void StmtProfiler::VisitExpr(Expr *S) {
VisitStmt(S);
}
@@ -952,6 +956,17 @@ void StmtProfiler::VisitObjCIsaExpr(ObjCIsaExpr *S) {
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);
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 938a686c2b..080bca2198 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -36,7 +36,10 @@ bool Qualifiers::isStrictSupersetOf(Qualifiers Other) const {
(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 @@ bool Type::isIncompleteType() const {
}
}
-/// 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(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(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(cast(CanonicalType)->getDecl()))
return ClassDecl->isPOD();
@@ -908,6 +931,121 @@ bool Type::isPODType() const {
}
}
+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()) {
+ if (const CXXRecordDecl *ClassDecl =
+ dyn_cast(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()) {
+ if (const CXXRecordDecl *ClassDecl =
+ dyn_cast(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 @@ bool Type::isLiteralType() const {
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 @@ bool Type::isLiteralType() const {
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()) {
- if (const CXXRecordDecl *ClassDecl =
- dyn_cast(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()) {
- if (const CXXRecordDecl *ClassDecl =
- dyn_cast(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 @@ bool Type::isStandardLayoutType() const {
// 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 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
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(this+1);
@@ -1423,6 +1522,12 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
Expr **noexSlot = reinterpret_cast(argSlot + numArgs);
*noexSlot = epi.NoexceptExpr;
}
+
+ if (epi.ConsumedArguments) {
+ bool *consumedArgs = const_cast(getConsumedArgsBuffer());
+ for (unsigned i = 0; i != numArgs; ++i)
+ consumedArgs[i] = epi.ConsumedArguments[i];
+ }
}
FunctionProtoType::NoexceptResult
@@ -1461,6 +1566,24 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
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 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
} 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 @@ void Type::ClearLinkageCache() {
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(canon))
+ canon = array->getElementType().getTypePtr();
+
+ if (const ObjCObjectPointerType *opt
+ = dyn_cast(canon)) {
+ // Class and Class don't require retension.
+ if (opt->getObjectType()->isObjCClass())
+ return true;
+ }
+
+ return false;
+}
+
+bool Type::isObjCNSObjectType() const {
+ if (const TypedefType *typedefType = dyn_cast(this))
+ return typedefType->getDecl()->hasAttr();
+ return false;
+}
+bool Type::isObjCRetainableType() const {
+ return isObjCObjectPointerType() ||
+ isBlockPointerType() ||
+ isObjCNSObjectType();
+}
+bool Type::isObjCIndirectLifetimeType() const {
+ if (isObjCLifetimeType())
+ return true;
+ if (const PointerType *OPT = getAs())
+ return OPT->getPointeeType()->isObjCIndirectLifetimeType();
+ if (const ReferenceType *Ref = getAs())
+ return Ref->getPointeeType()->isObjCIndirectLifetimeType();
+ if (const MemberPointerType *MemPtr = getAs())
+ 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();
+ 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 @@ bool Type::hasSizedVLAType() const {
}
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 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) {
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;
+}
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 4519606f6e..ccb456018d 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -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 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
// "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(T))
TC = AT->desugar()->getTypeClass();
@@ -114,15 +131,18 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
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 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
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 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
// 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 @@ void TypePrinter::printPointer(const PointerType *T, std::string &S) {
if (isa(T->getPointeeType()))
S = '(' + S + ')';
+ IncludeStrongLifetimeRAII Strong(Policy);
print(T->getPointeeType(), S);
}
@@ -209,6 +244,7 @@ void TypePrinter::printLValueReference(const LValueReferenceType *T,
if (isa(T->getPointeeTypeAsWritten()))
S = '(' + S + ')';
+ IncludeStrongLifetimeRAII Strong(Policy);
print(T->getPointeeTypeAsWritten(), S);
}
@@ -221,6 +257,7 @@ void TypePrinter::printRValueReference(const RValueReferenceType *T,
if (isa(T->getPointeeTypeAsWritten()))
S = '(' + S + ')';
+ IncludeStrongLifetimeRAII Strong(Policy);
print(T->getPointeeTypeAsWritten(), S);
}
@@ -236,6 +273,7 @@ void TypePrinter::printMemberPointer(const MemberPointerType *T,
if (isa(T->getPointeeType()))
S = '(' + S + ')';
+ IncludeStrongLifetimeRAII Strong(Policy);
print(T->getPointeeType(), S);
}
@@ -245,12 +283,14 @@ void TypePrinter::printConstantArray(const ConstantArrayType *T,
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 @@ void TypePrinter::printVariableArray(const VariableArrayType *T,
}
S += ']';
+ IncludeStrongLifetimeRAII Strong(Policy);
print(T->getElementType(), S);
}
@@ -291,6 +332,7 @@ void TypePrinter::printDependentSizedArray(const DependentSizedArrayType *T,
}
S += ']';
+ IncludeStrongLifetimeRAII Strong(Policy);
print(T->getElementType(), S);
}
@@ -518,6 +560,7 @@ void TypePrinter::printUnaryTransform(const UnaryTransformType *T,
if (!S.empty())
S = ' ' + S;
std::string Str;
+ IncludeStrongLifetimeRAII Strong(Policy);
print(T->getBaseType(), Str);
switch (T->getUTTKind()) {
@@ -552,6 +595,7 @@ void TypePrinter::AppendScope(DeclContext *DC, std::string &Buffer) {
Buffer += "";
} else if (ClassTemplateSpecializationDecl *Spec
= dyn_cast(DC)) {
+ IncludeStrongLifetimeRAII Strong(Policy);
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
std::string TemplateArgsStr
= TemplateSpecializationType::PrintTemplateArgumentList(
@@ -642,6 +686,7 @@ void TypePrinter::printTag(TagDecl *D, std::string &InnerString) {
Args = TemplateArgs.data();
NumArgs = TemplateArgs.size();
}
+ IncludeStrongLifetimeRAII Strong(Policy);
Buffer += TemplateSpecializationType::PrintTemplateArgumentList(Args,
NumArgs,
Policy);
@@ -677,18 +722,21 @@ void TypePrinter::printTemplateTypeParm(const TemplateTypeParmType *T,
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::printDependentName(const DependentNameType *T, std::string &S)
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::printPackExpansion(const PackExpansionType *T,
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 @@ void TypePrinter::printAttributed(const AttributedType *T,
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 @@ std::string Qualifiers::getAsString() const {
// 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 @@ void Qualifiers::getAsStringInternal(std::string &S,
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) {
diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp
index 9ac456f53a..c5b17fc77b 100644
--- a/lib/Analysis/ReachableCode.cpp
+++ b/lib/Analysis/ReachableCode.cpp
@@ -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 @@ static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1,
case Stmt::CXXTryStmtClass: {
return cast(S)->getHandler(0)->getCatchLoc();
}
+ case Expr::ObjCBridgedCastExprClass: {
+ const ObjCBridgedCastExpr *CSC = cast(S);
+ R1 = CSC->getSubExpr()->getSourceRange();
+ return CSC->getLParenLoc();
+ }
default: ;
}
R1 = S->getSourceRange();
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index 25dbcf0a6f..b5b48cb213 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -740,5 +740,10 @@ bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const {
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;
}
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index 4711faa1a5..109761c9dc 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -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
@@ -92,7 +93,8 @@ namespace {
KEYBORLAND = 0x100,
KEYOPENCL = 0x200,
KEYC1X = 0x400,
- KEYALL = 0x7ff
+ KEYARC = 0x800,
+ KEYALL = 0x0fff
};
}
@@ -120,7 +122,8 @@ static void AddKeyword(llvm::StringRef Keyword,
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;
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index dd167dca47..541a1ed595 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -84,15 +84,35 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
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
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index e5da703a61..ac47034325 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -347,13 +347,23 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) {
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 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
// 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(variable), type, VK_LValue,
@@ -603,15 +618,29 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
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 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
-
-
llvm::Constant *
CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
ASTContext &C = getContext();
@@ -1084,21 +1111,40 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
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 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
// 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 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
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;
+
+ // 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;
- if (!dtor && flags.empty()) 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 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
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 @@ public:
}
};
+/// 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(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 @@ generateByrefCopyHelper(CodeGenFunction &CGF,
SC_Static,
SC_None,
false, true);
+
CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation());
if (byrefInfo.needsCopy()) {
@@ -1449,6 +1568,52 @@ CodeGenFunction::buildByrefHelpers(const llvm::StructType &byrefType,
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 @@ namespace {
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);
}
};
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index 9bd18e5fde..35d61cfdd4 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -89,7 +89,7 @@ enum BlockFieldFlag_t {
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
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 05c11ceac6..712ec62bd4 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -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 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) {
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())
+ einfo = einfo.withProducesResult(true);
+
+ return getFunctionInfo(GetReturnType(MD->getResultType()), ArgTys, einfo);
}
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(GlobalDecl GD) {
@@ -262,7 +265,8 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
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 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy,
}
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 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
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(result);
+
+ llvm::SmallVector insnsToKill;
+
+ // Look for:
+ // %generator = bitcast %type1* %generator2 to %type2*
+ while (llvm::BitCastInst *bitcast = dyn_cast(generator)) {
+ // We would have emitted this as a constant if the operand weren't
+ // an Instruction.
+ generator = cast(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(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(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(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::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 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
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 @@ void CodeGenFunction::EmitDelegateCallArg(CallArgList &args,
return args.add(RValue::get(value), type);
}
+static bool isProvablyNull(llvm::Value *addr) {
+ return isa(addr);
+}
+
+static bool isProvablyNonNull(llvm::Value *addr) {
+ return isa(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(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(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()->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(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(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 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
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();
diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h
index 160a62eab3..343b944bf6 100644
--- a/lib/CodeGen/CGCall.h
+++ b/lib/CodeGen/CGCall.h
@@ -58,9 +58,44 @@ namespace CodeGen {
class CallArgList :
public llvm::SmallVector {
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::const_iterator writeback_iterator;
+ writeback_iterator writeback_begin() const { return Writebacks.begin(); }
+ writeback_iterator writeback_end() const { return Writebacks.end(); }
+
+ private:
+ llvm::SmallVector Writebacks;
};
/// FunctionArgList - Type for representing both the decl and type
@@ -88,6 +123,9 @@ namespace CodeGen {
/// Whether this function is noreturn.
bool NoReturn;
+ /// Whether this function is returns-retained.
+ bool ReturnsRetained;
+
unsigned NumArgs;
ArgInfo *Args;
@@ -100,7 +138,8 @@ namespace CodeGen {
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 @@ namespace CodeGen {
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 @@ namespace CodeGen {
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 @@ namespace CodeGen {
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);
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 5725d80b7d..066f0d5c7d 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -398,7 +398,8 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
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 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF,
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 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
// 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 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
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();
- if (!Record ||
- cast(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 @@ namespace {
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 @@ namespace {
// 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 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
getContext().getAsConstantArrayType(FieldType);
if (Array)
FieldType = getContext().getBaseElementType(Array->getElementType());
-
- const RecordType *RT = FieldType->getAs();
- if (!RT)
+
+ switch (FieldType.isDestructedType()) {
+ case QualType::DK_none:
continue;
-
- CXXRecordDecl *FieldClassDecl = cast(RT->getDecl());
- if (FieldClassDecl->hasTrivialDestructor())
- continue;
+
+ case QualType::DK_cxx_destructor:
+ if (Array)
+ EHStack.pushCleanup(NormalAndEHCleanup, Field);
+ else
+ EHStack.pushCleanup(NormalAndEHCleanup, Field);
+ break;
+
+ case QualType::DK_objc_strong_lifetime:
+ PushARCFieldReleaseCleanup(getARCCleanupKind(), Field);
+ break;
- if (Array)
- EHStack.pushCleanup(NormalAndEHCleanup, Field);
- else
- EHStack.pushCleanup(NormalAndEHCleanup, Field);
+ case QualType::DK_objc_weak_lifetime:
+ PushARCFieldWeakReleaseCleanup(getARCCleanupKind(), Field);
+ break;
+ }
}
}
@@ -1384,7 +1402,8 @@ CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor
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);
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 98d30db647..88cc5be4de 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -389,6 +389,7 @@ llvm::DIType CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DIFile Unit) {
// 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.
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 33c4ada68f..14e999f589 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -353,9 +353,7 @@ namespace {
if (NRVO) CGF.EmitBlock(SkipDtorBB);
}
};
-}
-namespace {
struct CallStackRestore : EHScopeStack::Cleanup {
llvm::Value *Stack;
CallStackRestore(llvm::Value *Stack) : Stack(Stack) {}
@@ -400,6 +398,164 @@ namespace {
};
}
+/// 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());
+ 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(s)) {
+ // Skip the most common kinds of expressions that make
+ // hierarchy-walking expensive.
+ s = e = e->IgnoreParenCasts();
+
+ if (const DeclRefExpr *ref = dyn_cast(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(decl)) return false;
+ const VarDecl *var = cast(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(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(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(D)));
+ }
+
+ const llvm::PointerType *ty = cast(tempAddr->getType());
+ ty = cast(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(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(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 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
// 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 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
/// \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(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(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 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
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 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
}
}
+ 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()) {
const FunctionDecl *FD = CA->getFunctionDecl();
@@ -847,6 +1012,22 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
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 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
// 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();
+
+ // '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(D)) {
+ const ObjCMethodDecl *method = cast(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(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];
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 178badd44d..08e8e0c48e 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -34,20 +34,22 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
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 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
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();
}
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index e8ad6da2f9..ce57d02bcd 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -354,7 +354,8 @@ static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *e,
// 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 @@ static void InitCatchParam(CodeGenFunction &CGF,
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();
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 525ad1b8f1..197bc67881 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -131,12 +131,12 @@ RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E) {
/// 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 @@ static llvm::Value *
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(E))
E = DAE->getExpr();
@@ -213,6 +216,7 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
return EmitExprForReferenceBinding(CGF, TE->getSubExpr(),
ReferenceTemporary,
ReferenceTemporaryDtor,
+ ObjCARCReferenceLifetimeType,
InitializedDecl);
}
@@ -279,12 +283,10 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
!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()) {
@@ -292,8 +294,37 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
if (!ClassDecl->hasTrivialDestructor())
ReferenceTemporaryDtor = ClassDecl->getDestructor();
}
+ else if (CGF.getContext().getLangOptions().ObjCAutoRefCount) {
+ if (const ValueDecl *InitVD = dyn_cast(InitializedDecl)) {
+ if (const ReferenceType *RefType
+ = InitVD->getType()->getAs()) {
+ 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 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E,
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(InitializedDecl)) {
- if (VD->hasGlobalStorage()) {
+ const VarDecl *VD = dyn_cast_or_null(InitializedDecl);
+ if (VD && VD->hasGlobalStorage()) {
+ if (ReferenceTemporaryDtor) {
llvm::Constant *DtorFn =
CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete);
EmitCXXGlobalDtorRegistration(DtorFn,
cast(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());
+ 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 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
case Expr::CXXDynamicCastExprClass:
case Expr::CXXReinterpretCastExprClass:
case Expr::CXXConstCastExprClass:
+ case Expr::ObjCBridgedCastExprClass:
return EmitCastLValue(cast(E));
}
}
@@ -668,6 +734,8 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, QualType ExprType) {
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 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
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 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV);
return;
}
-
+
+ if (const ObjCBridgedCastExpr *Exp = dyn_cast(E)) {
+ setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV);
+ return;
+ }
+
if (const ArraySubscriptExpr *Exp = dyn_cast(E)) {
setObjCGCLValueClass(Ctx, Exp->getBase(), LV);
if (LV.isObjCIvar() && !LV.isObjCArray())
@@ -1734,7 +1832,8 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr *E){
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 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
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 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
if (const CXXMethodDecl *MD = dyn_cast_or_null(TargetDecl))
return EmitCXXOperatorMemberCallExpr(CE, MD, ReturnValue);
- if (isa(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(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();
+ 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 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
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());
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index d8da642a6b..6d34499f38 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -339,6 +339,8 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
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 @@ AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV, QualType T) {
} 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 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
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 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
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 @@ static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E,
///
/// \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 @@ LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) {
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 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
llvm::Type::getInt8PtrTy(getLLVMContext(), SPT->getAddressSpace());
SrcPtr = Builder.CreateBitCast(SrcPtr, SBP, "tmp");
- if (const RecordType *RecordTy = Ty->getAs()) {
+ // 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()) {
RecordDecl *Record = RecordTy->getDecl();
if (Record->hasObjectMember()) {
CharUnits size = TypeInfo.first;
@@ -964,7 +972,7 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
SizeVal);
return;
}
- } else if (getContext().getAsArrayType(Ty)) {
+ } else if (Ty->isArrayType()) {
QualType BaseType = getContext().getBaseElementType(Ty);
if (const RecordType *RecordTy = BaseType->getAs()) {
if (RecordTy->getDecl()->hasObjectMember()) {
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 81fee677f6..434ca1b69f 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -708,15 +708,14 @@ static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const CXXNewExpr *E,
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 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// 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 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
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 @@ static void EmitArrayDelete(CodeGenFunction &CGF,
" 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();
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index da37bd5b0a..75e566110c 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -570,6 +570,8 @@ public:
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.
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index dff7bf45e0..6e42da8e01 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -1106,7 +1106,12 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
// 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::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
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)
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index cdb15bfd83..cdc2fffd94 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -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 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(addr->getType())->getElementType();
+ return llvm::ConstantPointerNull::get(cast(type));
+}
+
/// Emits an instance of NSConstantString representing the object.
llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E)
{
@@ -55,6 +69,7 @@ static RValue AdjustRelatedResultType(CodeGenFunction &CGF,
RValue Result) {
if (!Method)
return Result;
+
if (!Method->hasRelatedResultType() ||
CGF.getContext().hasSameType(E->getType(), Method->getResultType()) ||
!Result.isScalar())
@@ -71,6 +86,18 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
// 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());
+
CGObjCRuntime &Runtime = CGM.getObjCRuntime();
bool isSuperMessage = false;
bool isClassMessage = false;
@@ -80,8 +107,15 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
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 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
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 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
ReceiverType = E->getSuperType();
Receiver = LoadObjCSelf();
isSuperMessage = true;
+
+ if (retainSelf)
+ Receiver = EmitARCRetainNonBlock(Receiver);
break;
case ObjCMessageExpr::SuperClass:
@@ -106,14 +146,36 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
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(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 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
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(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(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(CGF.CurCodeDecl);
+ const ObjCImplementationDecl *impl
+ = cast(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 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
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(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 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
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 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
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 @@ namespace {
};
}
+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 @@ static void emitCXXDestructMethod(CodeGenFunction &CGF,
CGF.EHStack.pushCleanup(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 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
// Emit .cxx_construct.
if (ctor) {
+ // Suppress the final autorelease in ARC.
+ AutoreleaseResult = false;
+
llvm::SmallVector IvarInitializers;
for (ObjCImplementationDecl::init_const_iterator B = IMP->init_begin(),
E = IMP->init_end(); B != E; ++B) {
@@ -747,6 +889,16 @@ RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV,
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 @@ RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV,
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 @@ void CodeGenFunction::EmitObjCAtSynchronizedStmt(
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(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(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(value)) return value;
+
+ if (!fn) {
+ std::vector 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 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(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(addr->getType())->getElementType()
+ == value->getType());
+
+ if (!fn) {
+ std::vector 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 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(value)) return;
+
+ llvm::Constant *&fn = CGM.getARCEntrypoints().objc_release;
+ if (!fn) {
+ std::vector 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 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(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(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(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 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 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(arrayType)) {
+ vlaSizeInBytes = CGF.GetVLASize(cast(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(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 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(
+ cast(addr->getType())->getElementType());
+ while (true) {
+ assert(isa(arrayType));
+ assert(cast(arrayType)->getSize().getZExtValue()
+ == llvmArrayType->getNumElements());
+
+ gepIndices.push_back(zero);
+ countFromCLAs *= llvmArrayType->getNumElements();
+
+ llvmArrayType =
+ dyn_cast(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(NormalCleanup, Ptr);
+ else
+ EHStack.pushCleanup(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(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(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(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(cleanupKind, field);
+}
+
+static void pushReleaseForIvar(CodeGenFunction &CGF, ObjCIvarDecl *ivar,
+ llvm::Value *self) {
+ CGF.EHStack.pushCleanup(CGF.getARCCleanupKind(),
+ ivar, self);
+}
+
+static void pushWeakReleaseForIvar(CodeGenFunction &CGF, ObjCIvarDecl *ivar,
+ llvm::Value *self) {
+ CGF.EHStack.pushCleanup(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(e) &&
+ cast(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(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(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(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(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(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(e) ||
+ (isa(e) &&
+ !cast(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
+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, value);
+}
+
+std::pair
+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, value);
+}
+
+void CodeGenFunction::EmitObjCAutoreleasePoolStmt(
+ const ObjCAutoreleasePoolStmt &ARPS) {
+ const Stmt *subStmt = ARPS.getSubStmt();
+ const CompoundStmt &S = cast(*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(NormalCleanup, token);
+ } else {
+ llvm::Value *token = EmitObjCMRRAutoreleasePoolPush();
+ EHStack.pushCleanup(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() {}
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index f0993c5dad..e85c8980fe 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -969,7 +969,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
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 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
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,
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 8c3e9a36e3..988b16e945 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -63,10 +63,13 @@ private:
/// 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 @@ private:
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 @@ private:
/// 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 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
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 @@ static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) {
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 *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
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 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
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 @@ llvm::Constant *CGObjCMac::EmitModuleSymbols() {
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 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
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(FirstField));
+ }
+
for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
FieldDecl *Field = RecFields[i];
uint64_t FieldOffset;
@@ -3580,9 +3610,10 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
// 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(Field));
+ FieldOffset =
+ ComputeIvarBaseOffset(CGM, OI, cast(Field)) - FirstFieldDelta;
// Skip over unnamed or bitfields
if (!Field->getIdentifier() || Field->isBitField()) {
@@ -3861,12 +3892,16 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
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 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 RecFields;
for (unsigned k = 0, e = Ivars.size(); k != e; ++k)
@@ -4743,7 +4778,12 @@ enum MetaDataDlags {
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 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
const ObjCImplementationDecl *ID) {
std::string ClassName = ID->getNameAsString();
std::vector 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 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
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 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
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 @@ CGObjCNonFragileABIMac::GetClassGlobal(const std::string &Name) {
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) {
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index 866d5d83fe..7accc70c96 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -205,7 +205,13 @@ public:
/// 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;
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index a982621be7..187d5a6c3c 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -151,6 +151,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
case Stmt::ObjCForCollectionStmtClass:
EmitObjCForCollectionStmt(cast(*S));
break;
+ case Stmt::ObjCAutoreleasePoolStmtClass:
+ EmitObjCAutoreleasePoolStmt(cast(*S));
+ break;
case Stmt::CXXTryStmtClass:
EmitCXXTryStmt(cast(*S));
@@ -764,7 +767,7 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
} 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);
diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h
index 7f77d55203..1ad6628ec6 100644
--- a/lib/CodeGen/CGValue.h
+++ b/lib/CodeGen/CGValue.h
@@ -101,8 +101,6 @@ public:
/// 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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 {
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 150cb69b4d..6ab4b76e75 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -31,7 +31,7 @@ using namespace CodeGen;
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 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
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 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
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(D) && cast(D)->isInstance())
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index bb8fd8e243..f35022810f 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -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 @@ namespace clang {
class ObjCAtTryStmt;
class ObjCAtThrowStmt;
class ObjCAtSynchronizedStmt;
+ class ObjCAutoreleasePoolStmt;
namespace CodeGen {
class CodeGenTypes;
@@ -568,6 +570,10 @@ public:
/// 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 @@ public:
bool CatchUndefined;
+ /// In ARC, whether we should autorelease the return value.
+ bool AutoreleaseResult;
+
const CodeGen::CGBlockInfo *BlockInfo;
llvm::Value *BlockPointer;
@@ -1048,6 +1057,9 @@ public:
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 @@ public:
/// 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 @@ public:
/// 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 @@ public:
/// 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 @@ public:
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 @@ public:
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
+ EmitARCStoreAutoreleasing(const BinaryOperator *e);
+ std::pair
+ 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,
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 7a1a968259..78c57b4e3f 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -64,7 +64,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
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 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
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 @@ CodeGenModule::~CodeGenModule() {
delete &ABI;
delete TBAA;
delete DebugInfo;
+ delete ARCData;
+ delete RRData;
}
void CodeGenModule::createObjCRuntime() {
@@ -830,7 +836,8 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
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 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName,
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 @@ llvm::Constant *CodeGenModule::GetAddrOfFunction(GlobalDecl GD,
/// 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 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
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 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
ObjCMethodDecl::Required);
D->addInstanceMethod(CTORMethod);
CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true);
+ D->setHasCXXStructors(true);
}
/// EmitNamespace - Emit all declarations in a namespace.
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 09741dfada..7321ac45f4 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -131,6 +131,71 @@ namespace CodeGen {
/// 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 @@ class CodeGenModule : public CodeGenTypeCache {
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 @@ public:
/// 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 @@ public:
/// 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 @@ public:
/// 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 @@ private:
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,
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 12ef9bd030..7e71df1268 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -802,10 +802,27 @@ bool ItaniumCXXABI::NeedsArrayCookie(const CXXNewExpr *expr) {
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 @@ bool ItaniumCXXABI::NeedsArrayCookie(const CXXDeleteExpr *expr,
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 =
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 043ead7e62..9a6cc208e5 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -2277,6 +2277,10 @@ public:
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 @@ public:
return false;
}
-
-
};
}
diff --git a/lib/CodeGen/TargetInfo.h b/lib/CodeGen/TargetInfo.h
index 4f59eb619e..dbb09b1614 100644
--- a/lib/CodeGen/TargetInfo.h
+++ b/lib/CodeGen/TargetInfo.h
@@ -111,6 +111,20 @@ namespace clang {
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 "";
+ }
};
}
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index d919915410..8079e1983f 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -201,7 +201,8 @@ ToolChain::CXXStdlibType ToolChain::GetCXXStdlibType(const ArgList &Args) const{
}
void ToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
+ ArgStringList &CmdArgs,
+ bool ObjCXXAutoRefCount) const {
CXXStdlibType Type = GetCXXStdlibType(Args);
switch (Type) {
@@ -209,10 +210,16 @@ void ToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args,
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;
}
}
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index ca613e3d6c..35e7d80c29 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -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 @@ using namespace clang::driver::toolchains;
/// 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 @@ bool Darwin::HasNativeLLVMSupport() const {
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 @@ void DarwinClang::AddLinkSearchPathArgs(const ArgList &Args,
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 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
}
}
+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 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
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)
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index ace9b84791..7325874473 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -57,6 +57,16 @@ private:
// 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 @@ public:
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 @@ public:
virtual bool HasNativeLLVMSupport() const;
+ virtual bool HasARCRuntime() const;
+
virtual DerivedArgList *TranslateArgs(const DerivedArgList &Args,
const char *BoundArch) const;
@@ -257,6 +273,8 @@ public:
virtual void AddCCKextLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const;
+ virtual void AddLinkARCArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const;
/// }
};
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 0e85a9fd4f..1947827438 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -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 @@ static void AddLinkerInputs(const ToolChain &TC,
}
}
+/// \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 @@ void Clang::AddPreprocessingOptions(const Driver &D,
// 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 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
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) {
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index c929b4926d..1324926f94 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -169,6 +169,8 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
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 @@ static void LangOptsToArgs(const LangOptions &Opts,
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 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
(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 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
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 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
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(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,
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index 147a8df037..f1e1d47713 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -221,6 +221,125 @@ static void DefineExactWidthIntType(TargetInfo::IntType Ty,
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 \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 \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 \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 \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 struct __is_scalar;\n"
+ << "\n";
+
+ Out << "template