ArnaudBienner created this revision.
Herald added a subscriber: cfe-commits.

Repository:
  rC Clang

https://reviews.llvm.org/D56366

Files:
  include/clang/Basic/DiagnosticGroups.td
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaOverload.cpp
  test/Analysis/ctor.mm
  test/Analysis/dtor.cpp
  test/Analysis/virtualcall.cpp
  test/SemaCXX/warn-virtual-call-from-ctor-dtor.cpp

Index: test/SemaCXX/warn-virtual-call-from-ctor-dtor.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/warn-virtual-call-from-ctor-dtor.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -Wcall-to-virtual-from-ctor-dtor
+struct A {
+  A() { f(); } // expected-warning {{call to virtual member function 'f' from constructor of 'A' will not call overridden implementations}} expected-note {{qualify the call to silence this warning}}
+  ~A() { f(); } // expected-warning {{call to virtual member function 'f' from destructor of 'A' will not call overridden implementations}} expected-note {{qualify the call to silence this warning}}
+
+  virtual void f() {}
+};
+
+// Warns in classes inheriting from A too
+struct B : A {
+  B() { f(); } // expected-warning {{call to virtual member function 'f' from constructor of 'B' will not call overridden implementations}} expected-note {{qualify the call to silence this warning}}
+  ~B() { f(); } // expected-warning {{call to virtual member function 'f' from destructor of 'B' will not call overridden implementations}} expected-note {{qualify the call to silence this warning}}
+  void f() {}
+};
+
+// Don't warn if the class if final
+struct C final : A {
+  C() { f(); }
+  ~C() { f(); }
+};
+
+// Don't warn (or note) when calling the function on a pointer.
+struct D : A {
+  A *a;
+  D() { a->f(); };
+  ~D() { a->f(); };
+};
+
+// Don't warn if the call is fully qualified.
+struct E {
+  virtual void f() = 0;
+  E() {
+    E::f();
+  }
+};
Index: test/Analysis/virtualcall.cpp
===================================================================
--- test/Analysis/virtualcall.cpp
+++ test/Analysis/virtualcall.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -analyzer-output=text -verify -std=c++11 %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -analyzer-output=text -Wno-call-to-virtual-from-ctor-dtor -verify -std=c++11 %s
 
-// RUN: %clang_analyze_cc1 -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -analyzer-config optin.cplusplus.VirtualCall:PureOnly=true -DPUREONLY=1 -analyzer-output=text -verify -std=c++11 %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -analyzer-config optin.cplusplus.VirtualCall:PureOnly=true -DPUREONLY=1 -analyzer-output=text -Wno-call-to-virtual-from-ctor-dtor -verify -std=c++11 %s
 
 #include "virtualcall.h"
 
Index: test/Analysis/dtor.cpp
===================================================================
--- test/Analysis/dtor.cpp
+++ test/Analysis/dtor.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection,cplusplus -analyzer-config c++-inlining=destructors -Wno-null-dereference -Wno-inaccessible-base -verify -analyzer-config eagerly-assume=false %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection,cplusplus -analyzer-config c++-inlining=destructors -Wno-null-dereference -Wno-inaccessible-base -Wno-call-to-virtual-from-ctor-dtor -verify -analyzer-config eagerly-assume=false %s
 
 void clang_analyzer_eval(bool);
 void clang_analyzer_checkInlined(bool);
Index: test/Analysis/ctor.mm
===================================================================
--- test/Analysis/ctor.mm
+++ test/Analysis/ctor.mm
@@ -1,7 +1,7 @@
-// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -DI386 -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -std=c++11 -verify -analyzer-config eagerly-assume=false %s
-// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -DI386 -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -std=c++11 -verify -DTEST_INLINABLE_ALLOCATORS -analyzer-config eagerly-assume=false %s
-// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin12 -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -std=c++11 -verify -analyzer-config eagerly-assume=false %s
-// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin12 -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -std=c++11 -verify -DTEST_INLINABLE_ALLOCATORS -analyzer-config eagerly-assume=false %s
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -DI386 -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -Wno-call-to-virtual-from-ctor-dtor -std=c++11 -verify -analyzer-config eagerly-assume=false %s
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -DI386 -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -Wno-call-to-virtual-from-ctor-dtor -std=c++11 -verify -DTEST_INLINABLE_ALLOCATORS -analyzer-config eagerly-assume=false %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin12 -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -Wno-call-to-virtual-from-ctor-dtor -std=c++11 -verify -analyzer-config eagerly-assume=false %s
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin12 -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -Wno-call-to-virtual-from-ctor-dtor -std=c++11 -verify -DTEST_INLINABLE_ALLOCATORS -analyzer-config eagerly-assume=false %s
 
 #include "Inputs/system-header-simulator-cxx.h"
 
Index: lib/Sema/SemaOverload.cpp
===================================================================
--- lib/Sema/SemaOverload.cpp
+++ lib/Sema/SemaOverload.cpp
@@ -13071,6 +13071,36 @@
     }
   }
 
+  if ((isa<CXXConstructorDecl>(CurContext) ||
+       isa<CXXDestructorDecl>(CurContext)) &&
+      isa<CXXThisExpr>(MemExpr->getBase()->IgnoreParenCasts()) &&
+      TheCall->getMethodDecl()->isVirtual() &&
+      !MemExpr->hasQualifier() &&
+      // We already have a warning for pure virtual functions above, so don't
+      // consider them here
+      !TheCall->getMethodDecl()->isPure()) {
+    const CXXMethodDecl *CallMD = TheCall->getMethodDecl();
+    // dynamic casting CurnContext to CXXMethodDecl here is fine since we know
+    // from the check above that CurnContext is either CXXConstructorDecl or
+    // CXXDestructorDecl, which both inherit from CXXMethodDecl.
+    const CXXMethodDecl *ContextMD = dyn_cast<CXXMethodDecl>(CurContext);
+    assert(ContextMD && "CurContext was expected be a method declaration");
+    const CXXRecordDecl *ContextRD = ContextMD->getParent();
+    // A final class cannot be derived from, so issue a warning only if not
+    // final
+    if (ContextRD->isPolymorphic() && !ContextRD->hasAttr<FinalAttr>()) {
+      Diag(MemExpr->getBeginLoc(),
+           diag::warn_call_to_virtual_member_function_from_ctor_dtor)
+          << CallMD->getDeclName() << isa<CXXDestructorDecl>(CurContext)
+          << ContextMD->getParent()->getDeclName();
+      Diag(MemExpr->getBeginLoc(),
+           diag::note_call_to_virtual_member_function_from_ctor_dtor_silence)
+          << FixItHint::CreateInsertion(
+                 MemExpr->getBeginLoc(),
+                 ContextMD->getParent()->getDeclName().getAsString() + "::");
+    }
+  }
+
   if (CXXDestructorDecl *DD =
           dyn_cast<CXXDestructorDecl>(TheCall->getMethodDecl())) {
     // a->A::f() doesn't go through the vtable, except in AppleKext mode.
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -1625,6 +1625,12 @@
   "overrides of %0 in subclasses are not available in the "
   "%select{constructor|destructor}1 of %2">, InGroup<PureVirtualCallFromCtorDtor>;
 
+def warn_call_to_virtual_member_function_from_ctor_dtor : Warning<
+  "call to virtual member function %0 from %select{constructor|destructor}1 of %2 "
+  "will not call overridden implementations">, InGroup<VirtualCallFromCtorDtor>;
+def note_call_to_virtual_member_function_from_ctor_dtor_silence : Note<
+  "qualify the call to silence this warning">;
+
 def select_special_member_kind : TextSubstitution<
   "%select{default constructor|copy constructor|move constructor|"
   "copy assignment operator|move assignment operator|destructor}0">;
Index: include/clang/Basic/DiagnosticGroups.td
===================================================================
--- include/clang/Basic/DiagnosticGroups.td
+++ include/clang/Basic/DiagnosticGroups.td
@@ -288,6 +288,7 @@
 def IncrementBool : DiagGroup<"increment-bool", [DeprecatedIncrementBool]>;
 def InfiniteRecursion : DiagGroup<"infinite-recursion">;
 def PureVirtualCallFromCtorDtor: DiagGroup<"call-to-pure-virtual-from-ctor-dtor">;
+def VirtualCallFromCtorDtor: DiagGroup<"call-to-virtual-from-ctor-dtor">;
 def GNUImaginaryConstant : DiagGroup<"gnu-imaginary-constant">;
 def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">;
 def : DiagGroup<"import">;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to