summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Sema/AnalysisBasedWarnings.cpp120
-rw-r--r--clang/lib/Sema/Sema.cpp126
-rw-r--r--clang/lib/Sema/SemaDecl.cpp15
-rw-r--r--clang/lib/Sema/SemaExpr.cpp13
-rw-r--r--clang/lib/Sema/SemaPseudoObject.cpp35
5 files changed, 308 insertions, 1 deletions
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index a3aee9afe08..86e9dc2d648 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -871,6 +871,121 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
}
namespace {
+ typedef std::pair<const Stmt *,
+ sema::FunctionScopeInfo::WeakObjectUseMap::const_iterator>
+ StmtUsesPair;
+}
+
+template<>
+class BeforeThanCompare<StmtUsesPair> {
+ const SourceManager &SM;
+
+public:
+ explicit BeforeThanCompare(const SourceManager &SM) : SM(SM) { }
+
+ bool operator()(const StmtUsesPair &LHS, const StmtUsesPair &RHS) {
+ return SM.isBeforeInTranslationUnit(LHS.first->getLocStart(),
+ RHS.first->getLocStart());
+ }
+};
+
+
+static void diagnoseRepeatedUseOfWeak(Sema &S,
+ const sema::FunctionScopeInfo *CurFn,
+ const Decl *D) {
+ typedef sema::FunctionScopeInfo::WeakObjectProfileTy WeakObjectProfileTy;
+ typedef sema::FunctionScopeInfo::WeakObjectUseMap WeakObjectUseMap;
+ typedef sema::FunctionScopeInfo::WeakUseVector WeakUseVector;
+
+ const WeakObjectUseMap &WeakMap = CurFn->getWeakObjectUses();
+
+ // Extract all weak objects that are referenced more than once.
+ SmallVector<StmtUsesPair, 8> UsesByStmt;
+ for (WeakObjectUseMap::const_iterator I = WeakMap.begin(), E = WeakMap.end();
+ I != E; ++I) {
+ const WeakUseVector &Uses = I->second;
+ if (Uses.size() <= 1)
+ continue;
+
+ // Find the first read of the weak object.
+ WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end();
+ for ( ; UI != UE; ++UI) {
+ if (UI->isUnsafe())
+ break;
+ }
+
+ // If there were only writes to this object, don't warn.
+ if (UI == UE)
+ continue;
+
+ UsesByStmt.push_back(StmtUsesPair(UI->getUseExpr(), I));
+ }
+
+ if (UsesByStmt.empty())
+ return;
+
+ // Sort by first use so that we emit the warnings in a deterministic order.
+ std::sort(UsesByStmt.begin(), UsesByStmt.end(),
+ BeforeThanCompare<StmtUsesPair>(S.getSourceManager()));
+
+ // Classify the current code body for better warning text.
+ // This enum should stay in sync with the cases in
+ // warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak.
+ // FIXME: Should we use a common classification enum and the same set of
+ // possibilities all throughout Sema?
+ enum {
+ Function,
+ Method,
+ Block,
+ Lambda
+ } FunctionKind;
+
+ if (isa<sema::BlockScopeInfo>(CurFn))
+ FunctionKind = Block;
+ else if (isa<sema::LambdaScopeInfo>(CurFn))
+ FunctionKind = Lambda;
+ else if (isa<ObjCMethodDecl>(D))
+ FunctionKind = Method;
+ else
+ FunctionKind = Function;
+
+ // Iterate through the sorted problems and emit warnings for each.
+ for (SmallVectorImpl<StmtUsesPair>::const_iterator I = UsesByStmt.begin(),
+ E = UsesByStmt.end();
+ I != E; ++I) {
+ const Stmt *FirstRead = I->first;
+ const WeakObjectProfileTy &Key = I->second->first;
+ const WeakUseVector &Uses = I->second->second;
+
+ // For complicated expressions like self.foo.bar, it's hard to keep track
+ // of whether 'self.foo' is the same between two cases. We can only be
+ // 100% sure of a repeated use if the "base" part of the key is a variable,
+ // rather than, say, another property.
+ unsigned DiagKind;
+ if (Key.isExactProfile())
+ DiagKind = diag::warn_arc_repeated_use_of_weak;
+ else
+ DiagKind = diag::warn_arc_possible_repeated_use_of_weak;
+
+ // Show the first time the object was read.
+ S.Diag(FirstRead->getLocStart(), DiagKind)
+ << FunctionKind
+ << FirstRead->getSourceRange();
+
+ // Print all the other accesses as notes.
+ for (WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end();
+ UI != UE; ++UI) {
+ if (UI->getUseExpr() == FirstRead)
+ continue;
+ S.Diag(UI->getUseExpr()->getLocStart(),
+ diag::note_arc_weak_also_accessed_here)
+ << UI->getUseExpr()->getSourceRange();
+ }
+ }
+}
+
+
+namespace {
struct SLocSort {
bool operator()(const UninitUse &a, const UninitUse &b) {
// Prefer a more confident report over a less confident one.
@@ -1364,6 +1479,11 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
DiagnoseSwitchLabelsFallthrough(S, AC, !FallThroughDiagFull);
}
+ if (S.getLangOpts().ObjCARCWeak &&
+ Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
+ D->getLocStart()) != DiagnosticsEngine::Ignored)
+ diagnoseRepeatedUseOfWeak(S, fscope, D);
+
// Collect statistics about the CFG if it was built.
if (S.CollectStats && AC.isCFGBuilt()) {
++NumFunctionsAnalyzed;
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 08ccfa42598..84cdb2b6f04 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -54,6 +54,132 @@ void FunctionScopeInfo::Clear() {
Returns.clear();
ErrorTrap.reset();
PossiblyUnreachableDiags.clear();
+ WeakObjectUses.clear();
+}
+
+static const NamedDecl *getBestPropertyDecl(const ObjCPropertyRefExpr *PropE) {
+ if (PropE->isExplicitProperty())
+ return PropE->getExplicitProperty();
+
+ return PropE->getImplicitPropertyGetter();
+}
+
+static bool isSelfExpr(const Expr *E) {
+ E = E->IgnoreParenImpCasts();
+
+ const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E);
+ if (!DRE)
+ return false;
+
+ const ImplicitParamDecl *Param = dyn_cast<ImplicitParamDecl>(DRE->getDecl());
+ if (!Param)
+ return false;
+
+ const ObjCMethodDecl *M = dyn_cast<ObjCMethodDecl>(Param->getDeclContext());
+ if (!M)
+ return false;
+
+ return M->getSelfDecl() == Param;
+}
+
+FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy(
+ const ObjCPropertyRefExpr *PropE)
+ : Base(0, false), Property(getBestPropertyDecl(PropE)) {
+
+ if (PropE->isObjectReceiver()) {
+ const OpaqueValueExpr *OVE = cast<OpaqueValueExpr>(PropE->getBase());
+ const Expr *E = OVE->getSourceExpr()->IgnoreParenCasts();
+
+ switch (E->getStmtClass()) {
+ case Stmt::DeclRefExprClass:
+ Base.setPointer(cast<DeclRefExpr>(E)->getDecl());
+ Base.setInt(isa<VarDecl>(Base.getPointer()));
+ break;
+ case Stmt::MemberExprClass: {
+ const MemberExpr *ME = cast<MemberExpr>(E);
+ Base.setPointer(ME->getMemberDecl());
+ Base.setInt(isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()));
+ break;
+ }
+ case Stmt::ObjCIvarRefExprClass: {
+ const ObjCIvarRefExpr *IE = cast<ObjCIvarRefExpr>(E);
+ Base.setPointer(IE->getDecl());
+ if (isSelfExpr(IE->getBase()))
+ Base.setInt(true);
+ break;
+ }
+ case Stmt::PseudoObjectExprClass: {
+ const PseudoObjectExpr *POE = cast<PseudoObjectExpr>(E);
+ const ObjCPropertyRefExpr *BaseProp =
+ dyn_cast<ObjCPropertyRefExpr>(POE->getSyntacticForm());
+ if (BaseProp) {
+ Base.setPointer(getBestPropertyDecl(BaseProp));
+
+ const Expr *DoubleBase = BaseProp->getBase();
+ if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(DoubleBase))
+ DoubleBase = OVE->getSourceExpr();
+
+ if (isSelfExpr(DoubleBase))
+ Base.setInt(true);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ } else if (PropE->isClassReceiver()) {
+ Base.setPointer(PropE->getClassReceiver());
+ Base.setInt(true);
+ } else {
+ assert(PropE->isSuperReceiver());
+ Base.setInt(true);
+ }
+}
+
+void FunctionScopeInfo::recordUseOfWeak(const ObjCPropertyRefExpr *RefExpr) {
+ assert(RefExpr);
+ WeakUseVector &Uses =
+ WeakObjectUses[FunctionScopeInfo::WeakObjectProfileTy(RefExpr)];
+ Uses.push_back(WeakUseTy(RefExpr, RefExpr->isMessagingGetter()));
+}
+
+void FunctionScopeInfo::markSafeWeakUse(const Expr *E) {
+ E = E->IgnoreParenImpCasts();
+
+ if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) {
+ markSafeWeakUse(POE->getSyntacticForm());
+ return;
+ }
+
+ if (const ConditionalOperator *Cond = dyn_cast<ConditionalOperator>(E)) {
+ markSafeWeakUse(Cond->getTrueExpr());
+ markSafeWeakUse(Cond->getFalseExpr());
+ return;
+ }
+
+ if (const BinaryConditionalOperator *Cond =
+ dyn_cast<BinaryConditionalOperator>(E)) {
+ markSafeWeakUse(Cond->getCommon());
+ markSafeWeakUse(Cond->getFalseExpr());
+ return;
+ }
+
+ if (const ObjCPropertyRefExpr *RefExpr = dyn_cast<ObjCPropertyRefExpr>(E)) {
+ // Has this property been seen as a weak property?
+ FunctionScopeInfo::WeakObjectUseMap::iterator Uses =
+ WeakObjectUses.find(FunctionScopeInfo::WeakObjectProfileTy(RefExpr));
+ if (Uses == WeakObjectUses.end())
+ return;
+
+ // Has there been a read from the property using this Expr?
+ FunctionScopeInfo::WeakUseVector::reverse_iterator ThisUse =
+ std::find(Uses->second.rbegin(), Uses->second.rend(), WeakUseTy(E, true));
+ if (ThisUse == Uses->second.rend())
+ return;
+
+ ThisUse->markSafe();
+ return;
+ }
}
BlockScopeInfo::~BlockScopeInfo() { }
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 01aaf8be323..592956b9dbc 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -6588,6 +6588,21 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
if (VDecl->hasAttr<BlocksAttr>())
checkRetainCycles(VDecl, Init);
+
+ // It is safe to assign a weak reference into a strong variable.
+ // Although this code can still have problems:
+ // id x = self.weakProp;
+ // id y = self.weakProp;
+ // we do not warn to warn spuriously when 'x' and 'y' are on separate
+ // paths through the function. This should be revisited if
+ // -Wrepeated-use-of-weak is made flow-sensitive.
+ if (VDecl->getType().getObjCLifetime() == Qualifiers::OCL_Strong) {
+ DiagnosticsEngine::Level Level =
+ Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
+ Init->getLocStart());
+ if (Level != DiagnosticsEngine::Ignored)
+ getCurFunction()->markSafeWeakUse(Init);
+ }
}
Init = MaybeCreateExprWithCleanups(Init);
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 630281a4242..597e4d6f77c 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7726,6 +7726,19 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
if (!DRE || DRE->getDecl()->hasAttr<BlocksAttr>())
checkRetainCycles(LHSExpr, RHS.get());
+ // It is safe to assign a weak reference into a strong variable.
+ // Although this code can still have problems:
+ // id x = self.weakProp;
+ // id y = self.weakProp;
+ // we do not warn to warn spuriously when 'x' and 'y' are on separate
+ // paths through the function. This should be revisited if
+ // -Wrepeated-use-of-weak is made flow-sensitive.
+ DiagnosticsEngine::Level Level =
+ Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
+ RHS.get()->getLocStart());
+ if (Level != DiagnosticsEngine::Ignored)
+ getCurFunction()->markSafeWeakUse(RHS.get());
+
} else if (getLangOpts().ObjCAutoRefCount) {
checkUnsafeExprAssigns(Loc, LHSExpr, RHS.get());
}
diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp
index 31496b32a07..b07a59b81c2 100644
--- a/clang/lib/Sema/SemaPseudoObject.cpp
+++ b/clang/lib/Sema/SemaPseudoObject.cpp
@@ -31,6 +31,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/Initialization.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Lex/Preprocessor.h"
@@ -186,7 +187,7 @@ namespace {
UnaryOperatorKind opcode,
Expr *op);
- ExprResult complete(Expr *syntacticForm);
+ virtual ExprResult complete(Expr *syntacticForm);
OpaqueValueExpr *capture(Expr *op);
OpaqueValueExpr *captureValueAsResult(Expr *op);
@@ -238,6 +239,9 @@ namespace {
Expr *rebuildAndCaptureObject(Expr *syntacticBase);
ExprResult buildGet();
ExprResult buildSet(Expr *op, SourceLocation, bool);
+ ExprResult complete(Expr *SyntacticForm);
+
+ bool isWeakProperty() const;
};
/// A PseudoOpBuilder for Objective-C array/dictionary indexing.
@@ -471,6 +475,23 @@ static ObjCMethodDecl *LookupMethodInReceiverType(Sema &S, Selector sel,
return S.LookupMethodInObjectType(sel, IT, false);
}
+bool ObjCPropertyOpBuilder::isWeakProperty() const {
+ QualType T;
+ if (RefExpr->isExplicitProperty()) {
+ const ObjCPropertyDecl *Prop = RefExpr->getExplicitProperty();
+ if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak)
+ return true;
+
+ T = Prop->getType();
+ } else if (Getter) {
+ T = Getter->getResultType();
+ } else {
+ return false;
+ }
+
+ return T.getObjCLifetime() == Qualifiers::OCL_Weak;
+}
+
bool ObjCPropertyOpBuilder::findGetter() {
if (Getter) return true;
@@ -818,6 +839,18 @@ ObjCPropertyOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc,
return PseudoOpBuilder::buildIncDecOperation(Sc, opcLoc, opcode, op);
}
+ExprResult ObjCPropertyOpBuilder::complete(Expr *SyntacticForm) {
+ if (S.getLangOpts().ObjCAutoRefCount && isWeakProperty()) {
+ DiagnosticsEngine::Level Level =
+ S.Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak,
+ SyntacticForm->getLocStart());
+ if (Level != DiagnosticsEngine::Ignored)
+ S.getCurFunction()->recordUseOfWeak(SyntacticRefExpr);
+ }
+
+ return PseudoOpBuilder::complete(SyntacticForm);
+}
+
// ObjCSubscript build stuff.
//
OpenPOWER on IntegriCloud