From 12f669e3cd42b20eb3abd1e1a43b2fd9c7d8a923 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Tue, 11 Sep 2012 00:31:02 +0000 Subject: [PATCH] [analyzer] Member function calls that use qualified names are non-virtual. C++11 [expr.call]p1: ...If the selected function is non-virtual, or if the id-expression in the class member access expression is a qualified-id, that function is called. Otherwise, its final overrider in the dynamic type of the object expression is called. llvm-svn: 163577 --- .../Core/PathSensitive/CallEvent.h | 2 ++ clang/lib/StaticAnalyzer/Core/CallEvent.cpp | 12 +++++++++++ clang/test/Analysis/dtor.cpp | 20 +++++++++++++++++++ clang/test/Analysis/inline.cpp | 15 ++++++++++++++ 4 files changed, 49 insertions(+) diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h index 912eea0b370e..c403622c77c9 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -549,6 +549,8 @@ public: } virtual const Expr *getCXXThisExpr() const; + + virtual RuntimeDefinition getRuntimeDefinition() const; virtual Kind getKind() const { return CE_CXXMember; } diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index 50d16f972832..09ba21173ba5 100644 --- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -496,6 +496,18 @@ const Expr *CXXMemberCall::getCXXThisExpr() const { return getOriginExpr()->getImplicitObjectArgument(); } +RuntimeDefinition CXXMemberCall::getRuntimeDefinition() const { + // C++11 [expr.call]p1: ...If the selected function is non-virtual, or if the + // id-expression in the class member access expression is a qualified-id, + // that function is called. Otherwise, its final overrider in the dynamic type + // of the object expression is called. + if (const MemberExpr *ME = dyn_cast(getOriginExpr()->getCallee())) + if (ME->hasQualifier()) + return AnyFunctionCall::getRuntimeDefinition(); + + return CXXInstanceCall::getRuntimeDefinition(); +} + const Expr *CXXMemberOperatorCall::getCXXThisExpr() const { return getOriginExpr()->getArg(0); diff --git a/clang/test/Analysis/dtor.cpp b/clang/test/Analysis/dtor.cpp index 99c47d592069..f46194599d4e 100644 --- a/clang/test/Analysis/dtor.cpp +++ b/clang/test/Analysis/dtor.cpp @@ -281,3 +281,23 @@ namespace MultipleInheritanceVirtualDtors { SubclassB b; } } + +namespace ExplicitDestructorCall { + class VirtualDtor { + public: + virtual ~VirtualDtor() { + clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} + } + }; + + class Subclass : public VirtualDtor { + public: + virtual ~Subclass() { + clang_analyzer_checkInlined(false); // no-warning + } + }; + + void destroy(Subclass *obj) { + obj->VirtualDtor::~VirtualDtor(); + } +} diff --git a/clang/test/Analysis/inline.cpp b/clang/test/Analysis/inline.cpp index 6c7cfc14e895..b39b87101a53 100644 --- a/clang/test/Analysis/inline.cpp +++ b/clang/test/Analysis/inline.cpp @@ -325,3 +325,18 @@ namespace VirtualWithSisterCasts { clang_analyzer_eval(g->x == 42); // expected-warning{{TRUE}} } } + + +namespace QualifiedCalls { + void test(One *object) { + // This uses the One class from the top of the file. + clang_analyzer_eval(object->getNum() == 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(object->One::getNum() == 1); // expected-warning{{TRUE}} + clang_analyzer_eval(object->A::getNum() == 0); // expected-warning{{TRUE}} + + // getZero is non-virtual. + clang_analyzer_eval(object->getZero() == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(object->One::getZero() == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(object->A::getZero() == 0); // expected-warning{{TRUE}} +} +}