[cfe-commits] r152139 - in /cfe/trunk: include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp lib/StaticAnalyzer/Core/Environment.cpp lib/StaticAnalyzer/Core/ExprEngine.cpp test/Analysis/objc-arc.m test/Analysis/objc-bool.m test/Analysis/retain-release.m tools/scan-build/ccc-analyzer
Ted Kremenek
kremenek at apple.com
Tue Mar 6 12:06:12 PST 2012
Author: kremenek
Date: Tue Mar 6 14:06:12 2012
New Revision: 152139
URL: http://llvm.org/viewvc/llvm-project?rev=152139&view=rev
Log:
Add static analyzer support for new NSArray/NSDictionary/NSNumber literals.
Added:
cfe/trunk/test/Analysis/objc-bool.m
Modified:
cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
cfe/trunk/lib/StaticAnalyzer/Core/Environment.cpp
cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
cfe/trunk/test/Analysis/objc-arc.m
cfe/trunk/test/Analysis/retain-release.m
cfe/trunk/tools/scan-build/ccc-analyzer
Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h?rev=152139&r1=152138&r2=152139&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h Tue Mar 6 14:06:12 2012
@@ -16,6 +16,8 @@
#define LLVM_CLANG_GR_SVALBUILDER
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
@@ -216,6 +218,10 @@
BasicVals.getValue(integer->getValue(),
integer->getType()->isUnsignedIntegerOrEnumerationType()));
}
+
+ nonloc::ConcreteInt makeBoolVal(const ObjCBoolLiteralExpr *boolean) {
+ return makeTruthVal(boolean->getValue(), boolean->getType());
+ }
nonloc::ConcreteInt makeBoolVal(const CXXBoolLiteralExpr *boolean);
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp?rev=152139&r1=152138&r2=152139&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp Tue Mar 6 14:06:12 2012
@@ -1861,41 +1861,49 @@
if (!PrevT) {
const Stmt *S = cast<StmtPoint>(N->getLocation()).getStmt();
- if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
- // Get the name of the callee (if it is available).
- SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx);
- if (const FunctionDecl *FD = X.getAsFunctionDecl())
- os << "Call to function '" << *FD << '\'';
- else
- os << "function call";
+ if (isa<ObjCArrayLiteral>(S)) {
+ os << "NSArray literal is an object with a +0 retain count";
}
- else {
- assert(isa<ObjCMessageExpr>(S));
- // The message expression may have between written directly or as
- // a property access. Lazily determine which case we are looking at.
- os << (isPropertyAccess(S, N->getParentMap()) ? "Property" : "Method");
+ else if (isa<ObjCDictionaryLiteral>(S)) {
+ os << "NSDictionary literal is an object with a +0 retain count";
}
+ else {
+ if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
+ // Get the name of the callee (if it is available).
+ SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx);
+ if (const FunctionDecl *FD = X.getAsFunctionDecl())
+ os << "Call to function '" << *FD << '\'';
+ else
+ os << "function call";
+ }
+ else {
+ assert(isa<ObjCMessageExpr>(S));
+ // The message expression may have between written directly or as
+ // a property access. Lazily determine which case we are looking at.
+ os << (isPropertyAccess(S, N->getParentMap()) ? "Property" : "Method");
+ }
- if (CurrV.getObjKind() == RetEffect::CF) {
- os << " returns a Core Foundation object with a ";
- }
- else {
- assert (CurrV.getObjKind() == RetEffect::ObjC);
- os << " returns an Objective-C object with a ";
- }
+ if (CurrV.getObjKind() == RetEffect::CF) {
+ os << " returns a Core Foundation object with a ";
+ }
+ else {
+ assert (CurrV.getObjKind() == RetEffect::ObjC);
+ os << " returns an Objective-C object with a ";
+ }
- if (CurrV.isOwned()) {
- os << "+1 retain count";
+ if (CurrV.isOwned()) {
+ os << "+1 retain count";
- if (GCEnabled) {
- assert(CurrV.getObjKind() == RetEffect::CF);
- os << ". "
- "Core Foundation objects are not automatically garbage collected.";
+ if (GCEnabled) {
+ assert(CurrV.getObjKind() == RetEffect::CF);
+ os << ". "
+ "Core Foundation objects are not automatically garbage collected.";
+ }
+ }
+ else {
+ assert (CurrV.isNotOwned());
+ os << "+0 retain count";
}
- }
- else {
- assert (CurrV.isNotOwned());
- os << "+0 retain count";
}
PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
@@ -2295,6 +2303,8 @@
check::PostStmt<CastExpr>,
check::PostStmt<CallExpr>,
check::PostStmt<CXXConstructExpr>,
+ check::PostStmt<ObjCArrayLiteral>,
+ check::PostStmt<ObjCDictionaryLiteral>,
check::PostObjCMessage,
check::PreStmt<ReturnStmt>,
check::RegionChanges,
@@ -2439,7 +2449,10 @@
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
void checkPostStmt(const CXXConstructExpr *CE, CheckerContext &C) const;
+ void checkPostStmt(const ObjCArrayLiteral *AL, CheckerContext &C) const;
+ void checkPostStmt(const ObjCDictionaryLiteral *DL, CheckerContext &C) const;
void checkPostObjCMessage(const ObjCMessage &Msg, CheckerContext &C) const;
+
void checkSummary(const RetainSummary &Summ, const CallOrObjCMessage &Call,
CheckerContext &C) const;
@@ -2474,6 +2487,8 @@
void processNonLeakError(ProgramStateRef St, SourceRange ErrorRange,
RefVal::Kind ErrorKind, SymbolRef Sym,
CheckerContext &C) const;
+
+ void processObjCLiterals(CheckerContext &C, const Expr *Ex) const;
const ProgramPointTag *getDeadSymbolTag(SymbolRef sym) const;
@@ -2637,6 +2652,49 @@
checkSummary(*Summ, CallOrObjCMessage(CE, state, C.getLocationContext()), C);
}
+void RetainCountChecker::processObjCLiterals(CheckerContext &C,
+ const Expr *Ex) const {
+ ProgramStateRef state = C.getState();
+ const ExplodedNode *pred = C.getPredecessor();
+ for (Stmt::const_child_iterator it = Ex->child_begin(), et = Ex->child_end() ;
+ it != et ; ++it) {
+ const Stmt *child = *it;
+ SVal V = state->getSVal(child, pred->getLocationContext());
+ if (SymbolRef sym = V.getAsSymbol())
+ if (const RefVal* T = state->get<RefBindings>(sym)) {
+ RefVal::Kind hasErr = (RefVal::Kind) 0;
+ state = updateSymbol(state, sym, *T, MayEscape, hasErr, C);
+ if (hasErr) {
+ processNonLeakError(state, child->getSourceRange(), hasErr, sym, C);
+ return;
+ }
+ }
+ }
+
+ // Return the object as autoreleased.
+ // RetEffect RE = RetEffect::MakeNotOwned(RetEffect::ObjC);
+ if (SymbolRef sym =
+ state->getSVal(Ex, pred->getLocationContext()).getAsSymbol()) {
+ QualType ResultTy = Ex->getType();
+ state = state->set<RefBindings>(sym, RefVal::makeNotOwned(RetEffect::ObjC,
+ ResultTy));
+ }
+
+ C.addTransition(state);
+}
+
+void RetainCountChecker::checkPostStmt(const ObjCArrayLiteral *AL,
+ CheckerContext &C) const {
+ // Apply the 'MayEscape' to all values.
+ processObjCLiterals(C, AL);
+}
+
+void RetainCountChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
+ CheckerContext &C) const {
+ // Apply the 'MayEscape' to all keys and values.
+ processObjCLiterals(C, DL);
+}
+
void RetainCountChecker::checkPostObjCMessage(const ObjCMessage &Msg,
CheckerContext &C) const {
ProgramStateRef state = C.getState();
Modified: cfe/trunk/lib/StaticAnalyzer/Core/Environment.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/Environment.cpp?rev=152139&r1=152138&r2=152139&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/Environment.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/Environment.cpp Tue Mar 6 14:06:12 2012
@@ -79,6 +79,9 @@
else
return svalBuilder.makeIntVal(cast<IntegerLiteral>(E));
}
+ case Stmt::ObjCBoolLiteralExprClass:
+ return svalBuilder.makeBoolVal(cast<ObjCBoolLiteralExpr>(E));
+
// For special C0xx nullptr case, make a null pointer SVal.
case Stmt::CXXNullPtrLiteralExprClass:
return svalBuilder.makeNull();
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=152139&r1=152138&r2=152139&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Tue Mar 6 14:06:12 2012
@@ -555,6 +555,10 @@
Bldr.addNodes(Dst);
break;
+ // FIXME.
+ case Stmt::ObjCSubscriptRefExprClass:
+ break;
+
case Stmt::ObjCPropertyRefExprClass:
// Implicitly handled by Environment::getSVal().
break;
@@ -586,6 +590,7 @@
case Stmt::ObjCIsaExprClass:
case Stmt::ObjCProtocolExprClass:
case Stmt::ObjCSelectorExprClass:
+ case Expr::ObjCNumericLiteralClass:
case Stmt::ParenListExprClass:
case Stmt::PredefinedExprClass:
case Stmt::ShuffleVectorExprClass:
@@ -602,6 +607,7 @@
case Stmt::IntegerLiteralClass:
case Stmt::CharacterLiteralClass:
case Stmt::CXXBoolLiteralExprClass:
+ case Stmt::ObjCBoolLiteralExprClass:
case Stmt::FloatingLiteralClass:
case Stmt::SizeOfPackExprClass:
case Stmt::StringLiteralClass:
@@ -616,6 +622,36 @@
break;
}
+ case Expr::ObjCArrayLiteralClass:
+ case Expr::ObjCDictionaryLiteralClass: {
+ Bldr.takeNodes(Pred);
+
+ ExplodedNodeSet preVisit;
+ getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this);
+
+ // FIXME: explicitly model with a region and the actual contents
+ // of the container. For now, conjure a symbol.
+ ExplodedNodeSet Tmp;
+ StmtNodeBuilder Bldr2(preVisit, Tmp, *currentBuilderContext);
+
+ for (ExplodedNodeSet::iterator it = preVisit.begin(), et = preVisit.end();
+ it != et; ++it) {
+ ExplodedNode *N = *it;
+ const Expr *Ex = cast<Expr>(S);
+ QualType resultType = Ex->getType();
+ const LocationContext *LCtx = N->getLocationContext();
+ SVal result =
+ svalBuilder.getConjuredSymbolVal(0, Ex, LCtx, resultType,
+ currentBuilderContext->getCurrentBlockCount());
+ ProgramStateRef state = N->getState()->BindExpr(Ex, LCtx, result);
+ Bldr2.generateNode(S, N, state);
+ }
+
+ getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
+ Bldr.addNodes(Dst);
+ break;
+ }
+
case Stmt::ArraySubscriptExprClass:
Bldr.takeNodes(Pred);
VisitLvalArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Pred, Dst);
Modified: cfe/trunk/test/Analysis/objc-arc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/objc-arc.m?rev=152139&r1=152138&r2=152139&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/objc-arc.m (original)
+++ cfe/trunk/test/Analysis/objc-arc.m Tue Mar 6 14:06:12 2012
@@ -3,6 +3,7 @@
typedef signed char BOOL;
typedef struct _NSZone NSZone;
@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+typedef unsigned long NSUInteger;
@protocol NSObject
- (BOOL)isEqual:(id)object;
@@ -10,12 +11,30 @@
@protocol NSCopying
- (id)copyWithZone:(NSZone *)zone;
@end
- at protocol NSCoding
+ at protocol NSCoding;
+ at protocol NSMutableCopying;
+ at protocol NSFastEnumeration
- (void)encodeWithCoder:(NSCoder *)aCoder;
@end
+ at protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone;
+ at end
+ at protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
+ at end
@interface NSObject <NSObject> {}
+ (id)alloc;
+- (id)init;
+- (NSString *)description;
@end
+ at interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
+- (NSUInteger)count;
+- (id)initWithObjects:(const id [])objects count:(NSUInteger)cnt;
++ (id)arrayWithObject:(id)anObject;
++ (id)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt;
++ (id)arrayWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1)));
+- (id)initWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1)));
+- (id)initWithArray:(NSArray *)array;
+ at end
+
typedef const struct __CFAllocator * CFAllocatorRef;
extern const CFAllocatorRef kCFAllocatorDefault;
typedef double CFTimeInterval;
@@ -153,3 +172,32 @@
return x; // no-warning
}
+void test_objc_arrays() {
+ { // CASE ONE -- OBJECT IN ARRAY CREATED DIRECTLY
+ NSObject *o = [[NSObject alloc] init];
+ NSArray *a = [[NSArray alloc] initWithObjects:o, (void*)0];
+ [a description];
+ [o description];
+ }
+
+ { // CASE TWO -- OBJECT IN ARRAY CREATED BY DUPING AUTORELEASED ARRAY
+ NSObject *o = [[NSObject alloc] init];
+ NSArray *a1 = [NSArray arrayWithObjects:o, (void*)0];
+ NSArray *a2 = [[NSArray alloc] initWithArray:a1];
+ [a2 description];
+ [o description];
+ }
+
+ { // CASE THREE -- OBJECT IN RETAINED @[]
+ NSObject *o = [[NSObject alloc] init];
+ NSArray *a3 = @[o];
+ [a3 description];
+ [o description];
+ }
+ {
+ // CASE 4, verify analyzer still working.
+ CFCreateString(); // expected-warning {{leak}}
+ }
+}
+
+
Added: cfe/trunk/test/Analysis/objc-bool.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/objc-bool.m?rev=152139&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/objc-bool.m (added)
+++ cfe/trunk/test/Analysis/objc-bool.m Tue Mar 6 14:06:12 2012
@@ -0,0 +1,22 @@
+// RUN: %clang --analyze %s -o %t -verify
+
+// Test handling of ObjC bool literals.
+
+typedef signed char BOOL;
+
+void rdar_10597458() {
+ if (__objc_yes)
+ return;
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+}
+
+void rdar_10597458_b(BOOL b) {
+ if (b == __objc_no)
+ return;
+
+ if (b == __objc_no) {
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+ }
+}
Modified: cfe/trunk/test/Analysis/retain-release.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/retain-release.m?rev=152139&r1=152138&r2=152139&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/retain-release.m (original)
+++ cfe/trunk/test/Analysis/retain-release.m Tue Mar 6 14:06:12 2012
@@ -115,10 +115,15 @@
- (id)retain;
- (oneway void)release;
- (id)autorelease;
+- (NSString *)description;
- (id)init;
- at end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone;
- at end @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone;
- at end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
+ at end
+ at protocol NSCopying
+- (id)copyWithZone:(NSZone *)zone;
+ at end
+ at protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone;
+ at end
+ at protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
@end
@interface NSObject <NSObject> {}
+ (id)allocWithZone:(NSZone *)zone;
@@ -132,13 +137,22 @@
typedef struct {
}
NSFastEnumerationState;
- at protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
- at end @class NSString, NSDictionary;
+ at protocol NSFastEnumeration
+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+ at end
+ at class NSString, NSDictionary;
@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value;
@end @interface NSNumber : NSValue - (char)charValue;
- (id)initWithInt:(int)value;
@end @class NSString;
- at interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count;
+ at interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
+- (NSUInteger)count;
+- (id)initWithObjects:(const id [])objects count:(NSUInteger)cnt;
++ (id)arrayWithObject:(id)anObject;
++ (id)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt;
++ (id)arrayWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1)));
+- (id)initWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1)));
+- (id)initWithArray:(NSArray *)array;
@end @interface NSArray (NSArrayCreation) + (id)array;
@end @interface NSAutoreleasePool : NSObject {
}
@@ -158,8 +172,12 @@
+ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length;
+ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b;
@end @class NSLocale, NSDate, NSCalendar, NSTimeZone, NSError, NSArray, NSMutableDictionary;
- at interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count;
- at end @interface NSMutableDictionary : NSDictionary - (void)removeObjectForKey:(id)aKey;
+ at interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
+- (NSUInteger)count;
++ (id)dictionaryWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id <NSCopying> [])keys count:(NSUInteger)cnt;
+ at end
+ at interface NSMutableDictionary : NSDictionary - (void)removeObjectForKey:(id)aKey;
- (void)setObject:(id)anObject forKey:(id)aKey;
@end @interface NSMutableDictionary (NSMutableDictionaryCreation) + (id)dictionaryWithCapacity:(NSUInteger)numItems;
@end typedef double CGFloat;
@@ -1629,3 +1647,52 @@
xpc_release(xpc);
}
+//===----------------------------------------------------------------------===//
+// ObjC literals support.
+//===----------------------------------------------------------------------===//
+
+void test_objc_arrays() {
+ { // CASE ONE -- OBJECT IN ARRAY CREATED DIRECTLY
+ NSObject *o = [[NSObject alloc] init];
+ NSArray *a = [[NSArray alloc] initWithObjects:o, (void*)0]; // expected-warning {{leak}}
+ [o release];
+ [a description];
+ [o description];
+ }
+
+ { // CASE TWO -- OBJECT IN ARRAY CREATED BY DUPING AUTORELEASED ARRAY
+ NSObject *o = [[NSObject alloc] init];
+ NSArray *a1 = [NSArray arrayWithObjects:o, (void*)0];
+ NSArray *a2 = [[NSArray alloc] initWithArray:a1]; // expected-warning {{leak}}
+ [o release];
+ [a2 description];
+ [o description];
+ }
+
+ { // CASE THREE -- OBJECT IN RETAINED @[]
+ NSObject *o = [[NSObject alloc] init];
+ NSArray *a3 = [@[o] retain]; // expected-warning {{leak}}
+ [o release];
+ [a3 description];
+ [o description];
+ }
+
+ { // CASE FOUR -- OBJECT IN ARRAY CREATED BY DUPING @[]
+ NSObject *o = [[NSObject alloc] init];
+ NSArray *a = [[NSArray alloc] initWithArray:@[o]]; // expected-warning {{leak}}
+ [o release];
+
+ [a description];
+ [o description];
+ }
+
+ { // CASE FIVE -- OBJECT IN RETAINED @{}
+ NSValue *o = [[NSValue alloc] init];
+ NSDictionary *a = [@{o : o} retain]; // expected-warning {{leak}}
+ [o release];
+
+ [a description];
+ [o description];
+ }
+}
+
Modified: cfe/trunk/tools/scan-build/ccc-analyzer
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/scan-build/ccc-analyzer?rev=152139&r1=152138&r2=152139&view=diff
==============================================================================
--- cfe/trunk/tools/scan-build/ccc-analyzer (original)
+++ cfe/trunk/tools/scan-build/ccc-analyzer Tue Mar 6 14:06:12 2012
@@ -345,7 +345,8 @@
);
my %LinkerOptionMap = (
- '-framework' => 1
+ '-framework' => 1,
+ '-fobjc-link-runtime' => 0
);
my %CompilerLinkerOptionMap = (
More information about the cfe-commits
mailing list