Index: test/Analysis/retain-release.m
===================================================================
--- test/Analysis/retain-release.m	(revision 152506)
+++ test/Analysis/retain-release.m	(working copy)
@@ -1661,7 +1661,7 @@
 
 void rdar_10824732() {
   @autoreleasepool {
-    NSString *obj = @"test";
+    id obj = [[NSObject alloc] init];
     RDar10824732 *foo = [[RDar10824732 alloc] initWithObj:obj]; // no-warning
     [foo release];
   }
@@ -1716,3 +1716,12 @@
     }
 }
 
+void testStringsAreAutoreleased() {
+  [@"abc" release]; // expected-warning{{Incorrect decrement of the reference count}}
+}
+
+void testStringsAreAutoreleased_indirect() {
+  NSObject *x = @"def";
+  [x release]; // expected-warning{{Incorrect decrement of the reference count}}
+}
+
Index: test/Analysis/retain-release-path-notes.m
===================================================================
--- test/Analysis/retain-release-path-notes.m	(revision 152506)
+++ test/Analysis/retain-release-path-notes.m	(working copy)
@@ -124,3 +124,8 @@
   return result; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'result' is returned from a method whose name ('getViolation') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'.  This violates the naming convention rules given in the Memory Management Guide for Cocoa}}
 }
 @end
+
+void testStringsAreAutoreleased() {
+  id x = @"def"; // expected-note{{NSString literal is an object with a +0 retain count}}
+  [x release]; // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} expected-note{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
+}
Index: lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp	(revision 152506)
+++ lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp	(working copy)
@@ -843,6 +843,64 @@
 } // end anonymous namespace
 
 //===----------------------------------------------------------------------===//
+// Symbols representing objects.
+//
+// For most objects this is simply their SymbolicRegion's conjured symbol,
+// but literals may have a more precise region.
+//
+// FIXME: This should probably not be limited to RetainCountChecker.
+//===----------------------------------------------------------------------===//
+
+namespace {
+  class ExtraObjectSymbols {
+  public:
+    typedef llvm::ImmutableMap<const MemRegion *, SymbolRef> EntryMap;    
+  };
+}
+
+namespace clang {
+namespace ento {
+template<> struct ProgramStateTrait<ExtraObjectSymbols>
+  : public ProgramStatePartialTrait<ExtraObjectSymbols::EntryMap> {
+  static inline void *GDMIndex() { static int tag; return &tag; }
+};
+} // end GR namespace
+} // end clang namespace
+
+static SymbolRef getSymbolForObject(ProgramStateRef state, SVal val) {
+  SymbolRef sym = val.getAsLocSymbol();
+  if (!sym) {
+    const MemRegion *MR = val.getAsRegion();
+    if (const SymbolRef *extraSym = state->get<ExtraObjectSymbols>(MR))
+      sym = *extraSym;
+  }
+  return sym;
+}
+
+static std::pair<ProgramStateRef, SymbolRef>
+makeSymbolForObject(ProgramStateRef state, SVal val, SValBuilder &SVB) {
+  const MemRegion *MR = val.getAsRegion();
+  if (!MR)
+    return std::make_pair((ProgramStateRef) 0, (SymbolRef) 0);
+
+  SymbolRef sym = NULL;
+  // Right now we only support string regions as extra objects.
+  if (const ObjCStringRegion *SR = dyn_cast<ObjCStringRegion>(MR)) {
+    const Expr *literal = SR->getObjCStringLiteral();
+    // Note the symbol's block-count of 0; it is not path-sensitive.
+    // This is okay because string literals are static data.
+    SVal obj = SVB.getMetadataSymbolVal(0, SR, literal, literal->getType(), 0);
+    sym = obj.getAsSymbol();
+    state = state->set<ExtraObjectSymbols>(SR, sym);
+  }
+
+  if (!sym)
+    return std::make_pair((ProgramStateRef) 0, (SymbolRef) 0);
+
+  return std::make_pair(state, sym);
+}
+
+//===----------------------------------------------------------------------===//
 // Implementation of checker data structures.
 //===----------------------------------------------------------------------===//
 
@@ -1348,7 +1406,7 @@
     // FIXME: Eventually replace the use of state->get<RefBindings> with
     // a generic API for reasoning about the Objective-C types of symbolic
     // objects.
-    if (SymbolRef Sym = receiverV.getAsLocSymbol())
+    if (SymbolRef Sym = getSymbolForObject(state, receiverV))
       if (const RefVal *T = state->get<RefBindings>(Sym))
         if (const ObjCObjectPointerType* PT =
             T->getType()->getAs<ObjCObjectPointerType>())
@@ -1612,6 +1670,7 @@
 //===----------------------------------------------------------------------===//
 // Error reporting.
 //===----------------------------------------------------------------------===//
+
 namespace {
   typedef llvm::DenseMap<const ExplodedNode *, const RetainSummary *>
     SummaryLogTy;
@@ -1897,6 +1956,9 @@
     else if (isa<ObjCDictionaryLiteral>(S)) {
       os << "NSDictionary literal is an object with a +0 retain count";
     }
+    else if (isa<ObjCStringLiteral>(S)) {
+      os << "NSString 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).
@@ -1961,7 +2023,8 @@
 
         // Retrieve the value of the argument.  Is it the symbol
         // we are interested in?
-        if (CurrSt->getSValAsScalarOrLoc(*AI, LCtx).getAsLocSymbol() != Sym)
+        SVal ArgVal = CurrSt->getSValAsScalarOrLoc(*AI, LCtx);
+        if (getSymbolForObject(CurrSt, ArgVal) != Sym)
           continue;
 
         // We have an argument.  Get the effect!
@@ -1969,12 +2032,13 @@
       }
     }
     else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) {
-      if (const Expr *receiver = ME->getInstanceReceiver())
-        if (CurrSt->getSValAsScalarOrLoc(receiver, LCtx)
-              .getAsLocSymbol() == Sym) {
+      if (const Expr *receiver = ME->getInstanceReceiver()) {
+        SVal receiverVal = CurrSt->getSValAsScalarOrLoc(receiver, LCtx);
+        if (getSymbolForObject(CurrSt, receiverVal) == Sym) {
           // The symbol we are tracking is the receiver.
           AEffects.push_back(Summ->getReceiverEffect());
         }
+      }
     }
   }
 
@@ -2111,11 +2175,13 @@
   // to Sym.
   for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end();
        I!=E; ++I)
-    if (const Expr *Exp = dyn_cast_or_null<Expr>(*I))
-      if (CurrSt->getSValAsScalarOrLoc(Exp, LCtx).getAsLocSymbol() == Sym) {
+    if (const Expr *Exp = dyn_cast_or_null<Expr>(*I)) {
+      SVal Val = CurrSt->getSValAsScalarOrLoc(Exp, LCtx);
+      if (getSymbolForObject(CurrSt, Val) == Sym) {
         P->addRange(Exp->getSourceRange());
         break;
       }
+    }
 
   return P;
 }
@@ -2324,6 +2390,7 @@
 namespace {
 class RetainCountChecker
   : public Checker< check::Bind,
+                    check::LiveSymbols,
                     check::DeadSymbols,
                     check::EndAnalysis,
                     check::EndPath,
@@ -2331,6 +2398,7 @@
                     check::PostStmt<CastExpr>,
                     check::PostStmt<CallExpr>,
                     check::PostStmt<CXXConstructExpr>,
+                    check::PostStmt<ObjCStringLiteral>,
                     check::PostStmt<ObjCArrayLiteral>,
                     check::PostStmt<ObjCDictionaryLiteral>,
                     check::PostObjCMessage,
@@ -2477,6 +2545,7 @@
 
   void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
   void checkPostStmt(const CXXConstructExpr *CE, CheckerContext &C) const;
+  void checkPostStmt(const ObjCStringLiteral *AL, 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;
@@ -2505,6 +2574,7 @@
                                 ExplodedNode *Pred, RetEffect RE, RefVal X,
                                 SymbolRef Sym, ProgramStateRef state) const;
                                               
+  void checkLiveSymbols(ProgramStateRef state, SymbolReaper &SR) const;
   void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
   void checkEndPath(CheckerContext &C) const;
 
@@ -2616,7 +2686,8 @@
   }
   
   ProgramStateRef state = C.getState();
-  SymbolRef Sym = state->getSVal(CE, C.getLocationContext()).getAsLocSymbol();
+  const LocationContext *LC = C.getLocationContext();
+  SymbolRef Sym = getSymbolForObject(state, state->getSVal(CE, LC));
   if (!Sym)
     return;
   const RefVal* T = state->get<RefBindings>(Sym);
@@ -2683,12 +2754,11 @@
 void RetainCountChecker::processObjCLiterals(CheckerContext &C,
                                              const Expr *Ex) const {
   ProgramStateRef state = C.getState();
-  const ExplodedNode *pred = C.getPredecessor();  
+  const LocationContext *LC = C.getLocationContext();
   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 (SymbolRef sym = getSymbolForObject(state, state->getSVal(child, LC)))
       if (const RefVal* T = state->get<RefBindings>(sym)) {
         RefVal::Kind hasErr = (RefVal::Kind) 0;
         state = updateSymbol(state, sym, *T, MayEscape, hasErr, C);
@@ -2701,8 +2771,7 @@
   
   // Return the object as autoreleased.
   //  RetEffect RE = RetEffect::MakeNotOwned(RetEffect::ObjC);
-  if (SymbolRef sym = 
-        state->getSVal(Ex, pred->getLocationContext()).getAsSymbol()) {
+  if (SymbolRef sym = getSymbolForObject(state, state->getSVal(Ex, LC))) {
     QualType ResultTy = Ex->getType();
     state = state->set<RefBindings>(sym, RefVal::makeNotOwned(RetEffect::ObjC,
                                                               ResultTy));
@@ -2711,6 +2780,23 @@
   C.addTransition(state);  
 }
 
+void RetainCountChecker::checkPostStmt(const ObjCStringLiteral *AL,
+                                       CheckerContext &C) const {
+  ProgramStateRef state = C.getState();
+
+  SVal val = state->getSVal(AL, C.getLocationContext());
+  SymbolRef sym;
+  llvm::tie(state, sym) = makeSymbolForObject(state, val, C.getSValBuilder());
+  assert(state && "Could not associate a symbol with an ObjCStringLiteral.");
+  
+  // Treat the string as autoreleased.
+  QualType ResultTy = AL->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.
@@ -2785,7 +2871,7 @@
   for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {
     SVal V = CallOrMsg.getArgSVal(idx);
 
-    if (SymbolRef Sym = V.getAsLocSymbol()) {
+    if (SymbolRef Sym = getSymbolForObject(state, V)) {
       if (RefBindings::data_type *T = state->get<RefBindings>(Sym)) {
         state = updateSymbol(state, Sym, *T, Summ.getArg(idx), hasErr, C);
         if (hasErr) {
@@ -2802,7 +2888,7 @@
   if (!hasErr && CallOrMsg.isObjCMessage()) {
     const LocationContext *LC = C.getLocationContext();
     SVal Receiver = CallOrMsg.getInstanceMessageReceiver(LC);
-    if (SymbolRef Sym = Receiver.getAsLocSymbol()) {
+    if (SymbolRef Sym = getSymbolForObject(state, Receiver)) {
       if (const RefVal *T = state->get<RefBindings>(Sym)) {
         ReceiverIsTracked = true;
         state = updateSymbol(state, Sym, *T, Summ.getReceiverEffect(),
@@ -2841,8 +2927,9 @@
 
     case RetEffect::OwnedAllocatedSymbol:
     case RetEffect::OwnedSymbol: {
-      SymbolRef Sym = state->getSVal(CallOrMsg.getOriginExpr(),
-                                     C.getLocationContext()).getAsSymbol();
+      const Expr *Ex = CallOrMsg.getOriginExpr();
+      const LocationContext *LC = C.getLocationContext();
+      SymbolRef Sym = getSymbolForObject(state, state->getSVal(Ex, LC));
       if (!Sym)
         break;
 
@@ -2869,7 +2956,8 @@
     case RetEffect::ARCNotOwnedSymbol:
     case RetEffect::NotOwnedSymbol: {
       const Expr *Ex = CallOrMsg.getOriginExpr();
-      SymbolRef Sym = state->getSVal(Ex, C.getLocationContext()).getAsSymbol();
+      const LocationContext *LC = C.getLocationContext();
+      SymbolRef Sym = getSymbolForObject(state, state->getSVal(Ex, LC));
       if (!Sym)
         break;
 
@@ -3144,7 +3232,7 @@
   // considered alive during the next statement.
   if (const MemRegion *ArgRegion = RetVal.getAsRegion()) {
     // Save the refcount status of the argument.
-    SymbolRef Sym = RetVal.getAsLocSymbol();
+    SymbolRef Sym = getSymbolForObject(state, RetVal);
     RefBindings::data_type *Binding = 0;
     if (Sym)
       Binding = state->get<RefBindings>(Sym);
@@ -3188,8 +3276,9 @@
     return;
 
   ProgramStateRef state = C.getState();
-  SymbolRef Sym =
-    state->getSValAsScalarOrLoc(RetE, C.getLocationContext()).getAsLocSymbol();
+  SVal Val = state->getSValAsScalarOrLoc(RetE, C.getLocationContext());
+  SymbolRef Sym = getSymbolForObject(state, Val);
+
   if (!Sym)
     return;
 
@@ -3599,6 +3688,19 @@
   return tag;  
 }
 
+void RetainCountChecker::checkLiveSymbols(ProgramStateRef state,
+                                          SymbolReaper &SR) const {
+  // Mark all symbols in our extra object map as valid.
+  ExtraObjectSymbols::EntryMap Entries = state->get<ExtraObjectSymbols>();
+
+  for (ExtraObjectSymbols::EntryMap::iterator I = Entries.begin(),
+         E = Entries.end(); I != E; ++I) {
+    // Note that we are /not/ iterating over sub-symbols.
+    // This map should only have metadata symbols owned by the checker.
+    SR.markInUse(I.getData());
+  }
+}
+
 void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
                                           CheckerContext &C) const {
   ExplodedNode *Pred = C.getPredecessor();
Index: lib/StaticAnalyzer/Core/SymbolManager.cpp
===================================================================
--- lib/StaticAnalyzer/Core/SymbolManager.cpp	(revision 152506)
+++ lib/StaticAnalyzer/Core/SymbolManager.cpp	(working copy)
@@ -440,10 +440,12 @@
 
   // FIXME: This is a gross over-approximation. What we really need is a way to
   // tell if anything still refers to this region. Unlike SymbolicRegions,
-  // AllocaRegions don't have associated symbols, though, so we don't actually
+  // though, these regions don't have associated symbols, so we don't actually
   // have a way to track their liveness.
   if (isa<AllocaRegion>(MR))
     return true;
+  if (isa<ObjCStringRegion>(MR))
+    return true;
 
   if (isa<CXXThisRegion>(MR))
     return true;
