aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/ARCMigrate/ARCMT.h3
-rw-r--r--lib/ARCMigrate/ARCMT.cpp7
-rw-r--r--lib/ARCMigrate/Transforms.cpp44
-rw-r--r--lib/Frontend/CompilerInvocation.cpp1
-rw-r--r--test/ARCMT/GC-no-finalize-removal.m92
-rw-r--r--test/ARCMT/GC-no-finalize-removal.m.result100
-rw-r--r--tools/arcmt-test/arcmt-test.cpp3
7 files changed, 245 insertions, 5 deletions
diff --git a/include/clang/ARCMigrate/ARCMT.h b/include/clang/ARCMigrate/ARCMT.h
index b05dd4c95d..738a00dcd0 100644
--- a/include/clang/ARCMigrate/ARCMT.h
+++ b/include/clang/ARCMigrate/ARCMT.h
@@ -78,7 +78,8 @@ bool getFileRemappings(std::vector<std::pair<std::string,std::string> > &remap,
typedef void (*TransformFn)(MigrationPass &pass);
-std::vector<TransformFn> getAllTransformations(LangOptions::GCMode OrigGCMode);
+std::vector<TransformFn> getAllTransformations(LangOptions::GCMode OrigGCMode,
+ bool NoFinalizeRemoval);
class MigrationProcess {
CompilerInvocation OrigCI;
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp
index cd4835ef39..f9a1a75d87 100644
--- a/lib/ARCMigrate/ARCMT.cpp
+++ b/lib/ARCMigrate/ARCMT.cpp
@@ -232,7 +232,8 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
bool NoNSAllocReallocError = origCI.getMigratorOpts().NoNSAllocReallocError;
bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval;
- std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode);
+ std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode,
+ NoFinalizeRemoval);
assert(!transforms.empty());
llvm::OwningPtr<CompilerInvocation> CInvok;
@@ -337,8 +338,10 @@ static bool applyTransforms(CompilerInvocation &origCI,
CInvok.getFrontendOpts().Inputs.push_back(Input);
MigrationProcess migration(CInvok, DiagClient, outputDir);
+ bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval;
- std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode);
+ std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode,
+ NoFinalizeRemoval);
assert(!transforms.empty());
for (unsigned i=0, e = transforms.size(); i != e; ++i) {
diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp
index a64124015c..91121f0245 100644
--- a/lib/ARCMigrate/Transforms.cpp
+++ b/lib/ARCMigrate/Transforms.cpp
@@ -502,6 +502,45 @@ void MigrationContext::traverse(TranslationUnitDecl *TU) {
ASTTransform(*this).TraverseDecl(TU);
}
+static void GCRewriteFinalize(MigrationPass &pass) {
+ ASTContext &Ctx = pass.Ctx;
+ TransformActions &TA = pass.TA;
+ DeclContext *DC = Ctx.getTranslationUnitDecl();
+ Selector FinalizeSel =
+ Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize"));
+
+ typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl>
+ impl_iterator;
+ for (impl_iterator I = impl_iterator(DC->decls_begin()),
+ E = impl_iterator(DC->decls_end()); I != E; ++I) {
+ for (ObjCImplementationDecl::instmeth_iterator
+ MI = (*I)->instmeth_begin(),
+ ME = (*I)->instmeth_end(); MI != ME; ++MI) {
+ ObjCMethodDecl *MD = *MI;
+ if (!MD->hasBody())
+ continue;
+
+ if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) {
+ ObjCMethodDecl *FinalizeM = MD;
+ Transaction Trans(TA);
+ TA.insert(FinalizeM->getSourceRange().getBegin(),
+ "#if !__has_feature(objc_arc)\n");
+ CharSourceRange::getTokenRange(FinalizeM->getSourceRange());
+ const SourceManager &SM = pass.Ctx.getSourceManager();
+ const LangOptions &LangOpts = pass.Ctx.getLangOptions();
+ bool Invalid;
+ std::string str = "\n#endif\n";
+ str += Lexer::getSourceText(
+ CharSourceRange::getTokenRange(FinalizeM->getSourceRange()),
+ SM, LangOpts, &Invalid);
+ TA.insertAfterToken(FinalizeM->getSourceRange().getEnd(), str);
+
+ break;
+ }
+ }
+ }
+}
+
//===----------------------------------------------------------------------===//
// getAllTransformations.
//===----------------------------------------------------------------------===//
@@ -531,9 +570,12 @@ static void independentTransforms(MigrationPass &pass) {
}
std::vector<TransformFn> arcmt::getAllTransformations(
- LangOptions::GCMode OrigGCMode) {
+ LangOptions::GCMode OrigGCMode,
+ bool NoFinalizeRemoval) {
std::vector<TransformFn> transforms;
+ if (OrigGCMode == LangOptions::GCOnly && NoFinalizeRemoval)
+ transforms.push_back(GCRewriteFinalize);
transforms.push_back(independentTransforms);
// This depends on previous transformations removing various expressions.
transforms.push_back(removeEmptyStatementsAndDeallocFinalize);
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 5a0117af5a..a189155e12 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -1065,6 +1065,7 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
static bool ParseMigratorArgs(MigratorOptions &Opts, ArgList &Args) {
Opts.NoNSAllocReallocError = Args.hasArg(OPT_migrator_no_nsalloc_error);
+ Opts.NoFinalizeRemoval = Args.hasArg(OPT_migrator_no_finalize_removal);
return true;
}
diff --git a/test/ARCMT/GC-no-finalize-removal.m b/test/ARCMT/GC-no-finalize-removal.m
new file mode 100644
index 0000000000..d9739376f2
--- /dev/null
+++ b/test/ARCMT/GC-no-finalize-removal.m
@@ -0,0 +1,92 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.7 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fsyntax-only -fobjc-gc-only -no-finalize-removal -x objective-c %s > %t
+// RUN: diff %t %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fsyntax-only -fobjc-gc-only -no-finalize-removal -x objective-c++ %s > %t
+// RUN: diff %t %s.result
+// DISABLE: mingw32
+
+#include "Common.h"
+#include "GC.h"
+
+void test1(CFTypeRef *cft) {
+ id x = NSMakeCollectable(cft);
+}
+
+@interface I1 {
+ __strong I1 *myivar;
+}
+@end
+
+@implementation I1
+-(void)dealloc {
+ // dealloc
+ test1(0);
+}
+
+-(void)finalize {
+ // finalize
+ test1(0);
+}
+@end
+
+@interface I2
+@property (retain) id prop;
+@end
+
+@implementation I2
+@synthesize prop;
+
+-(void)finalize {
+ self.prop = 0;
+ // finalize
+ test1(0);
+}
+@end
+
+__attribute__((objc_arc_weak_reference_unavailable))
+@interface QQ {
+ __weak id s;
+ __weak QQ *q;
+}
+@end
+
+@interface I3
+@property (assign) I3 *__weak pw1, *__weak pw2;
+@property (assign) I3 *__strong ps;
+@property (assign) I3 * pds;
+@end
+
+@interface I4Impl {
+ I4Impl *pds2;
+ I4Impl *pds3;
+ __weak I4Impl *pw3;
+ __weak I4Impl *pw4;
+}
+@property (assign) I4Impl *__weak pw1, *__weak pw2;
+@property (assign) I4Impl *__strong ps;
+@property (assign) I4Impl * pds;
+@property (assign) I4Impl * pds2;
+@property (readwrite) I4Impl * pds3;
+@property (readonly) I4Impl * pds4;
+@property (readonly) __weak I4Impl *pw3;
+@property (assign) __weak I4Impl *pw4;
+@end
+
+@implementation I4Impl
+@synthesize pw1, pw2, pw3, pw4, ps, pds, pds2, pds3, pds4;
+
+-(void)test1:(CFTypeRef *)cft {
+ id x = NSMakeCollectable(cft);
+}
+@end
+
+// rdar://10532449
+@interface rdar10532449
+@property (assign) id assign_prop;
+@property (assign, readonly) id __strong strong_readonly_prop;
+@property (assign) id __weak weak_prop;
+@end
+
+@implementation rdar10532449
+@synthesize assign_prop, strong_readonly_prop, weak_prop;
+@end
diff --git a/test/ARCMT/GC-no-finalize-removal.m.result b/test/ARCMT/GC-no-finalize-removal.m.result
new file mode 100644
index 0000000000..38aabc32ae
--- /dev/null
+++ b/test/ARCMT/GC-no-finalize-removal.m.result
@@ -0,0 +1,100 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.7 -fsyntax-only -fobjc-runtime-has-weak -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fsyntax-only -fobjc-gc-only -no-finalize-removal -x objective-c %s > %t
+// RUN: diff %t %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-macosx10.7 -fsyntax-only -fobjc-gc-only -no-finalize-removal -x objective-c++ %s > %t
+// RUN: diff %t %s.result
+// DISABLE: mingw32
+
+#include "Common.h"
+#include "GC.h"
+
+void test1(CFTypeRef *cft) {
+ id x = CFBridgingRelease(cft);
+}
+
+@interface I1 {
+ I1 *myivar;
+}
+@end
+
+@implementation I1
+-(void)dealloc {
+ // dealloc
+ test1(0);
+}
+
+#if !__has_feature(objc_arc)
+-(void)finalize {
+ // finalize
+ test1(0);
+}
+#endif
+@end
+
+@interface I2
+@property (strong) id prop;
+@end
+
+@implementation I2
+@synthesize prop;
+
+#if !__has_feature(objc_arc)
+-(void)finalize {
+ self.prop = 0;
+ // finalize
+ test1(0);
+}
+#endif
+-(void)dealloc {
+ // finalize
+ test1(0);
+}
+@end
+
+__attribute__((objc_arc_weak_reference_unavailable))
+@interface QQ {
+ __weak id s;
+ __unsafe_unretained QQ *q;
+}
+@end
+
+@interface I3
+@property (weak) I3 * pw1, * pw2;
+@property (strong) I3 * ps;
+@property (assign) I3 * pds;
+@end
+
+@interface I4Impl {
+ I4Impl *__strong pds2;
+ I4Impl *pds3;
+ __weak I4Impl *pw3;
+ __weak I4Impl *pw4;
+}
+@property (weak) I4Impl * pw1, * pw2;
+@property (strong) I4Impl * ps;
+@property (strong) I4Impl * pds;
+@property (strong) I4Impl * pds2;
+@property (readwrite) I4Impl * pds3;
+@property (readonly) I4Impl * pds4;
+@property (weak, readonly) I4Impl *pw3;
+@property (weak) I4Impl *pw4;
+@end
+
+@implementation I4Impl
+@synthesize pw1, pw2, pw3, pw4, ps, pds, pds2, pds3, pds4;
+
+-(void)test1:(CFTypeRef *)cft {
+ id x = CFBridgingRelease(cft);
+}
+@end
+
+// rdar://10532449
+@interface rdar10532449
+@property (strong) id assign_prop;
+@property (strong, readonly) id strong_readonly_prop;
+@property (weak) id weak_prop;
+@end
+
+@implementation rdar10532449
+@synthesize assign_prop, strong_readonly_prop, weak_prop;
+@end
diff --git a/tools/arcmt-test/arcmt-test.cpp b/tools/arcmt-test/arcmt-test.cpp
index 9523ebcba0..6efb707950 100644
--- a/tools/arcmt-test/arcmt-test.cpp
+++ b/tools/arcmt-test/arcmt-test.cpp
@@ -173,7 +173,8 @@ static bool performTransformations(StringRef resourcesPath,
MigrationProcess migration(origCI, DiagClient);
std::vector<TransformFn>
- transforms = arcmt::getAllTransformations(origCI.getLangOpts()->getGC());
+ transforms = arcmt::getAllTransformations(origCI.getLangOpts()->getGC(),
+ origCI.getMigratorOpts().NoFinalizeRemoval);
assert(!transforms.empty());
llvm::OwningPtr<PrintTransforms> transformPrinter;