summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Kramer <benny.kra@googlemail.com>2014-08-21 10:25:03 +0000
committerBenjamin Kramer <benny.kra@googlemail.com>2014-08-21 10:25:03 +0000
commitcb4efc1028778b31ffb2401befa8a70640cc5dc4 (patch)
tree538a418fb4aaca4386cf6b9a119601378de23448
parent3ecaf02be9c4d284cc9b9bbed3143a492f901e0f (diff)
downloadbcm5719-llvm-cb4efc1028778b31ffb2401befa8a70640cc5dc4.tar.gz
bcm5719-llvm-cb4efc1028778b31ffb2401befa8a70640cc5dc4.zip
[analyzer] Don't warn on virtual calls in ctors to final methods.
The call will never go to a more derived class, but that's intentional in those cases. llvm-svn: 216167
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp13
-rw-r--r--clang/test/Analysis/virtualcall.cpp23
2 files changed, 32 insertions, 4 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
index f8f5cf93ca8..7e1fc1eb54a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
@@ -146,15 +146,22 @@ void WalkAST::VisitCXXMemberCallExpr(CallExpr *CE) {
if (CME->getQualifier())
callIsNonVirtual = true;
- // Elide analyzing the call entirely if the base pointer is not 'this'.
- if (Expr *base = CME->getBase()->IgnoreImpCasts())
+ if (Expr *base = CME->getBase()->IgnoreImpCasts()) {
+ // Elide analyzing the call entirely if the base pointer is not 'this'.
if (!isa<CXXThisExpr>(base))
return;
+
+ // If the most derived class is marked final, we know that now subclass
+ // can override this member.
+ if (base->getBestDynamicClassType()->hasAttr<FinalAttr>())
+ callIsNonVirtual = true;
+ }
}
// Get the callee.
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CE->getDirectCallee());
- if (MD && MD->isVirtual() && !callIsNonVirtual)
+ if (MD && MD->isVirtual() && !callIsNonVirtual && !MD->hasAttr<FinalAttr>() &&
+ !MD->getParent()->hasAttr<FinalAttr>())
ReportVirtualCall(CE, MD->isPure());
Enqueue(CE);
diff --git a/clang/test/Analysis/virtualcall.cpp b/clang/test/Analysis/virtualcall.cpp
index c3319b0ac54..8ce1d4103b9 100644
--- a/clang/test/Analysis/virtualcall.cpp
+++ b/clang/test/Analysis/virtualcall.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.cplusplus.VirtualCall -analyzer-store region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.cplusplus.VirtualCall -analyzer-store region -verify -std=c++11 %s
class A {
public:
@@ -46,10 +46,31 @@ C::C() {
f(foo()); // expected-warning{{Call virtual functions during construction or destruction will never go to a more derived class}}
}
+class D : public B {
+public:
+ D() {
+ foo(); // no-warning
+ }
+ ~D() { bar(); }
+ int foo() final;
+ void bar() final { foo(); } // no-warning
+};
+
+class E final : public B {
+public:
+ E() {
+ foo(); // no-warning
+ }
+ ~E() { bar(); }
+ int foo() override;
+};
+
int main() {
A *a;
B *b;
C *c;
+ D *d;
+ E *e;
}
#include "virtualcall.h"
OpenPOWER on IntegriCloud