teemperor updated this revision to Diff 54343.
teemperor added a comment.

- Fixed indentation


http://reviews.llvm.org/D19312

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaDeclCXX.cpp
  test/SemaCXX/ctor-init-with-member-call.cpp

Index: test/SemaCXX/ctor-init-with-member-call.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/ctor-init-with-member-call.cpp
@@ -0,0 +1,77 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 -Wmember-call-in-ctor-init
+
+// Helper class for the following test cases.
+class A {
+public:
+  A(int i) {
+  }
+};
+
+// Calling member functions before bass class initialized is undefined behavior.
+class B : public A {
+public:
+
+  B() : A(1 + get_i()) { // expected-warning {{member function call this->get_i() in ctor-initializer for base class 'A' results in undefined behavior}}
+  }
+
+  int get_i() {
+    return 2;
+  }
+};
+
+// Same as previous test but with explicit this.
+class C : public A {
+public:
+  C() : A(this->get_i() + 1) { // expected-warning {{member function call this->get_i() in ctor-initializer for base class 'A' results in undefined behavior}}
+  }
+
+  int get_i() {
+    return 2;
+  }
+};
+
+// Check that the whole ctor-initializer is checked for member calls.
+class OtherA {
+public:
+  OtherA(int i) {
+  }
+};
+
+class D : public OtherA, public A {
+public:
+  D() : OtherA(this->get_i() + 1), A(this->get_i() + 1) { // expected-warning {{member function call this->get_i() in ctor-initializer for base class 'OtherA' results in undefined behavior}} \
+                                                          // expected-warning {{member function call this->get_i() in ctor-initializer for base class 'A' results in undefined behavior}}
+  }
+
+  int get_i() {
+    return 2;
+  }
+};
+
+// Calling static functions of this class is not undefined behavior.
+class E : public A {
+public:
+  E() : A(this->get_i() + 1) { // no-warning
+  }
+
+  static int get_i() {
+    return 2;
+  }
+};
+
+
+// Calling other functions of this class is not undefined behavior.
+int other_foo() {
+  return 2;
+}
+class F : public A {
+public:
+  F() : A(other_foo()) {} // no-warning
+};
+
+
+// Calling member functions of other classes is not undefined behavior.
+class G : public A {
+public:
+  G(B& b) : A(b.get_i()) {} // no-warning
+};
\ No newline at end of file
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -3873,6 +3873,35 @@
   return false;
 }
 
+namespace {
+  /// \brief Searches for the first member function call to a given class.
+  class HasMemberCall : public RecursiveASTVisitor<HasMemberCall> {
+    CXXRecordDecl* OnlyForClass;
+    CXXMemberCallExpr *FoundMemberCall = nullptr;
+
+  public:
+    explicit HasMemberCall(CXXRecordDecl* OnlyForClass)
+      : OnlyForClass(OnlyForClass) {
+    }
+
+    /// \brief Returns the found member function call or 0 if
+    /// no fitting member function call was found.
+    CXXMemberCallExpr *getFoundMemberCall() {
+      return FoundMemberCall;
+    }
+
+    bool VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
+      // Check if member call is actually to the given class.
+      if (E->getRecordDecl() == nullptr
+          || E->getRecordDecl()->getCanonicalDecl() == OnlyForClass) {
+        FoundMemberCall = E;
+        return false;
+      }
+      return true;
+    }
+  };
+}
+
 bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
                                ArrayRef<CXXCtorInitializer *> Initializers) {
   if (Constructor->isDependentContext()) {
@@ -3907,9 +3936,24 @@
   for (unsigned i = 0; i < Initializers.size(); i++) {
     CXXCtorInitializer *Member = Initializers[i];
 
-    if (Member->isBaseInitializer())
+    if (Member->isBaseInitializer()) {
+      // Calling a member function from a ctor-initializer
+      // before the base class results in undefined behavior [12.6.2 16].
+      // FIXME: We only check for member functions directly called from this
+      // CtorInitializer and not for indirectly called functions.
+      HasMemberCall Finder(ClassDecl);
+      Finder.TraverseStmt(Member->getInit());
+
+      if (Finder.getFoundMemberCall()) {
+        Diag(Member->getSourceLocation(), diag::warn_member_call_in_ctor_init)
+          << Finder.getFoundMemberCall()
+          << Member->getBaseClass()->getAsCXXRecordDecl();
+      }
+
+
+
       Info.AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member;
-    else {
+    } else {
       Info.AllBaseFields[Member->getAnyMember()->getCanonicalDecl()] = Member;
 
       if (IndirectFieldDecl *F = Member->getIndirectMember()) {
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -6791,6 +6791,10 @@
   "will never be used">,
   InGroup<DiagGroup<"abstract-vbase-init">>, DefaultIgnore;
 
+def warn_member_call_in_ctor_init : Warning<
+  "member function call %0 in ctor-initializer for base class %1 results in undefined behavior">,
+  InGroup<DiagGroup<"member-call-in-ctor-init">>, DefaultIgnore;
+
 def err_base_init_does_not_name_class : Error<
   "constructor initializer %0 does not name a class">;
 def err_base_init_direct_and_virtual : Error<
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to