Re: [PATCH] D19312: Warn about UB at member function calls from base class ctor initializers.

2016-04-30 Thread Raphael Isemann via cfe-commits
teemperor updated this revision to Diff 55716.
teemperor added a comment.

Merged all tests into one file.


http://reviews.llvm.org/D19312

Files:
  include/clang/Basic/DiagnosticGroups.td
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaDeclCXX.cpp
  test/SemaCXX/warn-undefined-in-ctor.cpp

Index: test/SemaCXX/warn-undefined-in-ctor.cpp
===
--- /dev/null
+++ test/SemaCXX/warn-undefined-in-ctor.cpp
@@ -0,0 +1,174 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s -Wundefined-call-from-ctor
+
+// Warn about member function calls
+namespace MemberFunctionCallsTests {
+
+  // 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 {
+int member_;
+
+  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}}
+}
+B(float var)
+: A(sizeof(get_i())) { // no-warning
+}
+B(int var) : A(0), member_(get_i()) {} // no-warning
+
+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 ) : A(b.get_i()) {} // no-warning
+  };
+}
+
+
+
+// Warn about member function calls - example code from [C++11 12.6.2 p13]
+namespace MemberFunctionCallsStdTests {
+
+  class A {
+  public:
+A(int);
+  };
+
+  class B : public A {
+int j;
+
+  public:
+int f();
+B()
+: A(f()),   // expected-warning {{member function call this->f() in ctor-initializer for base class 'A' results in undefined behavior}}
+  j(f()) {} // no-warning
+  };
+
+  class C {
+  public:
+C(int);
+  };
+  class D : public B, C {
+int i;
+
+  public:
+D()
+: C(f()),   // expected-warning {{member function call this->f() in ctor-initializer for base class 'C' results in undefined behavior}}
+  i(f()) {} // no-warning
+  };
+
+}
+
+
+
+
+// Warn about dynamic_cast on this
+namespace DynamicCastTests {
+
+  // Helper class for the following test case.
+  class A {
+  public:
+A(A *a) {}
+A(unsigned long a) {}
+  };
+
+  // Calling dynamic cast on this before base class is initialized is undefined
+  // behavior.
+  class B : public A {
+
+A *j;
+
+  public:
+B()
+: A(dynamic_cast(this) + 1), j(nullptr) { // expected-warning {{dynamic_cast with this as operand in ctor-initializer for base class 'A' results in undefined behavior}}
+}
+B(float var)
+: A(sizeof(dynamic_cast(this) + 1)), j(nullptr) { // no-warning
+}
+B(int var) : A(nullptr), j(dynamic_cast(this)) {} // no-warning
+  };
+}
+
+
+
+// Warn about typeid on this
+namespace std {
+  class type_info {
+  };
+}
+
+namespace TypeidTests {
+
+  class A {
+  public:
+A(const std::type_info& a) {}
+A(unsigned a) {}
+  };
+
+  // Calling dynamic cast on this before base class is initialized is undefined
+  // behavior.
+  class B : public A {
+
+const std::type_info& j;
+
+  public:
+B()
+: A(typeid(this)), j(typeid(nullptr)) { // expected-warning {{typeid with this as operand in ctor-initializer for base class 'A' results in undefined behavior}}
+}
+B(float var)
+: A(sizeof(typeid(this))), j(typeid(nullptr)) { // no-warning
+}
+B(int var) : A(typeid(nullptr)), j(typeid(this)) {} // no-warning
+  };
+
+}
Index: lib/Sema/SemaDeclCXX.cpp

Re: [PATCH] D19312: Warn about UB at member function calls from base class ctor initializers.

2016-04-27 Thread Raphael Isemann via cfe-commits
teemperor updated this revision to Diff 55245.
teemperor added a comment.

- Added checks and tests for typeid
- Moved warnings into same warning group
- Check that only possibly evaluated expressions are checked


http://reviews.llvm.org/D19312

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

Index: test/SemaCXX/ctor-init-with-typeid.cpp
===
--- /dev/null
+++ test/SemaCXX/ctor-init-with-typeid.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s  %s -std=c++11 -Wundefined-call-from-ctor
+
+namespace std {
+  class type_info {
+  };
+}
+
+
+class A {
+public:
+  A(const std::type_info& a) {}
+  A(unsigned a) {}
+};
+
+// Calling dynamic cast on this before base class is initialized is undefined
+// behavior.
+class B : public A {
+
+  const std::type_info& j;
+
+public:
+  B()
+  : A(typeid(this)), j(typeid(nullptr)) { // expected-warning {{typeid with this as operand in ctor-initializer for base class 'A' results in undefined behavior}}
+  }
+  B(float var)
+  : A(sizeof(typeid(this))), j(typeid(nullptr)) { // no-warning
+  }
+  B(int var) : A(typeid(nullptr)), j(typeid(this)) {} // no-warning
+};
Index: test/SemaCXX/ctor-init-with-member-call.cpp
===
--- /dev/null
+++ test/SemaCXX/ctor-init-with-member-call.cpp
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -Wundefined-call-from-ctor
+
+// 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 {
+  int member_;
+
+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}}
+  }
+  B(float var)
+  : A(sizeof(get_i())) { // no-warning
+  }
+  B(int var) : A(0), member_(get_i()) {} // no-warning
+
+  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 ) : A(b.get_i()) {} // no-warning
+};
Index: test/SemaCXX/ctor-init-with-member-call-std.cpp
===
--- /dev/null
+++ test/SemaCXX/ctor-init-with-member-call-std.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -Wundefined-call-from-ctor
+
+// Test UB in ctor-initializer with the example from [C++11 12.6.2 p13]
+class A {
+public:
+  A(int);
+};
+
+class B : public A {
+  int j;
+
+public:
+  int f();
+  B()
+  : A(f()),   // expected-warning {{member function call this->f() in ctor-initializer for base class 'A' results in undefined behavior}}
+j(f()) {} // no-warning
+};
+
+class C {
+public:
+  C(int);
+};
+class D : public B, C {
+  int i;
+
+public:
+  D()
+  : C(f()),   // expected-warning {{member function call this->f() in ctor-initializer for base class 'C' results in undefined behavior}}
+i(f()) {} // no-warning
+};
Index: test/SemaCXX/ctor-init-with-dynamic-cast.cpp
===
--- /dev/null
+++ test/SemaCXX/ctor-init-with-dynamic-cast.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 -Wundefined-call-from-ctor
+
+// Helper class for the following test case.
+class A {
+public:
+  A(A *a) {}
+  A(unsigned long a) {}
+};
+
+// Calling 

Re: [PATCH] D19312: Warn about UB at member function calls from base class ctor initializers.

2016-04-27 Thread Raphael Isemann via cfe-commits
teemperor updated this revision to Diff 55189.
teemperor added a comment.

- Moved checks to the UninitializedFieldVisitor
- Also check for dynamic_cast on this during construction


http://reviews.llvm.org/D19312

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaDeclCXX.cpp
  test/SemaCXX/ctor-init-with-dynamic-cast.cpp
  test/SemaCXX/ctor-init-with-member-call-std.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,68 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -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 {
+  int member_;
+
+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}}
+  }
+  B(int var) : A(0), member_(get_i()) {} // no-warning
+
+  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 ) : A(b.get_i()) {} // no-warning
+};
Index: test/SemaCXX/ctor-init-with-member-call-std.cpp
===
--- /dev/null
+++ test/SemaCXX/ctor-init-with-member-call-std.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -Wmember-call-in-ctor-init
+
+// Test UB in ctor-initializer with the example from [C++11 12.6.2 p13]
+class A {
+public:
+  A(int);
+};
+
+class B : public A {
+  int j;
+
+public:
+  int f();
+  B()
+  : A(f()),   // expected-warning {{member function call this->f() in ctor-initializer for base class 'A' results in undefined behavior}}
+j(f()) {} // no-warning
+};
+
+class C {
+public:
+  C(int);
+};
+class D : public B, C {
+  int i;
+
+public:
+  D()
+  : C(f()),   // expected-warning {{member function call this->f() in ctor-initializer for base class 'C' results in undefined behavior}}
+i(f()) {} // no-warning
+};
Index: test/SemaCXX/ctor-init-with-dynamic-cast.cpp
===
--- /dev/null
+++ test/SemaCXX/ctor-init-with-dynamic-cast.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 -Wdynamic-cast-in-ctor-init
+
+// Helper class for the following test case.
+class A {
+public:
+  A(A *a) {}
+};
+
+// Calling dynamic cast on this before base class is initialized is undefined
+// behavior.
+class B : public A {
+
+  A *j;
+
+public:
+  B()
+  : A(dynamic_cast(this) + 1), j(nullptr) { // expected-warning {{dynamic_cast with this as operand in ctor-initializer for base class 'A' results in undefined behavior}}
+  }
+  B(int var) : A(nullptr), j(dynamic_cast(this)) {} // no-warning
+};
Index: lib/Sema/SemaDeclCXX.cpp
===
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -2290,6 +2290,9 @@
 bool InitList;
 FieldDecl *InitListFieldDecl;
 llvm::SmallVector InitFieldIndex;
+// The base class that is initialized by the current CXXCtorInitializer
+// or 0 if the current CXXCtorInitializer isn't initializing a base class.
+const Type *CurrentBaseClass;
 
   public:
 typedef EvaluatedExprVisitor Inherited;
@@ -2488,6 +2491,7 @@
 
   Constructor = FieldConstructor;
   InitListExpr *ILE = dyn_cast(E);
+  CurrentBaseClass = BaseClass;
 
   if (ILE && Field) {
 InitList = 

Re: [PATCH] D19312: Warn about UB at member function calls from base class ctor initializers.

2016-04-21 Thread Richard Trieu via cfe-commits
rtrieu added a subscriber: rtrieu.
rtrieu added a comment.

Have you looked at http://reviews.llvm.org/D6561 which was a previous attempt 
at this warning?


http://reviews.llvm.org/D19312



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D19312: Warn about UB at member function calls from base class ctor initializers.

2016-04-21 Thread Filipe Cabecinhas via cfe-commits
filcab added a comment.

The patch needs to get through clang-format.
Should we deal with typeid and dynamic_cast, since they're mentioned in the 
same paragraph in the standard?



Comment at: lib/Sema/SemaDeclCXX.cpp:3895
@@ +3894,3 @@
+  // Check if member call is actually to the given class.
+  if (E->getRecordDecl() == nullptr
+  || E->getRecordDecl()->getCanonicalDecl() == OnlyForClass

What's the rationale for warning if `getRecordDecl` returns `nullptr`?


Comment at: lib/Sema/SemaDeclCXX.cpp:3897
@@ +3896,3 @@
+  || E->getRecordDecl()->getCanonicalDecl() == OnlyForClass
+ || OnlyForClass->isDerivedFrom(E->getRecordDecl())) {
+FoundMemberCall = E;

Please run clang-format on the patch.


Comment at: lib/Sema/SemaDeclCXX.cpp:3941
@@ +3940,3 @@
+if (Member->isBaseInitializer()) {
+  // Calling a member function from a ctor-initializer
+  // before the base class results in undefined behavior [C++11 12.6.2 
p13].

clang-format


Comment at: lib/Sema/SemaDeclCXX.cpp:3942
@@ +3941,3 @@
+  // Calling a member function from a ctor-initializer
+  // before the base class results in undefined behavior [C++11 12.6.2 
p13].
+  // FIXME: We only check for member functions directly called from this

"before the base class is initialized"?



http://reviews.llvm.org/D19312



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D19312: Warn about UB at member function calls from base class ctor initializers.

2016-04-21 Thread Raphael Isemann via cfe-commits
teemperor updated this revision to Diff 54464.
teemperor added a comment.

- Standard reference is now specifying what standard (C++11)
- Added test based on the standard example
- Also check base classes now for member calls (to pass the test from the 
standard example).


http://reviews.llvm.org/D19312

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaDeclCXX.cpp
  test/SemaCXX/ctor-init-with-member-call-std.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,80 @@
+// 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 {
+  int member_;
+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}}
+  }
+  B(int var) : A(0), member_(get_i()) { } // no-warning
+
+  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
+};
+
Index: test/SemaCXX/ctor-init-with-member-call-std.cpp
===
--- /dev/null
+++ test/SemaCXX/ctor-init-with-member-call-std.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 -Wmember-call-in-ctor-init
+
+// Test UB in ctor-initializer with the example from [C++11 12.6.2 p13]
+class A {
+public:
+  A(int);
+};
+
+class B : public A {
+  int j;
+public:
+  int f();
+  B() : A(f()), // expected-warning {{member function call this->f() in ctor-initializer for base class 'A' results in undefined behavior}}
+  j(f()) { } // no-warning
+};
+
+class C {
+public:
+  C(int);
+};
+class D : public B, C {
+  int i;
+public:
+  D() : C(f()), // expected-warning {{member function call this->f() in ctor-initializer for base class 'C' results in undefined behavior}}
+  i(f()) { } // no-warning
+};
+
Index: lib/Sema/SemaDeclCXX.cpp
===
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -3873,6 +3873,36 @@
   return false;
 }
 
+namespace {
+  /// \brief Searches for the first member function call to a given class.
+  class HasMemberCall : public RecursiveASTVisitor {
+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
+	  || OnlyForClass->isDerivedFrom(E->getRecordDecl())) {
+FoundMemberCall = E;
+return false;
+  }
+  return true;
+}
+  };
+}
+
 bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
ArrayRef Initializers) {
   if (Constructor->isDependentContext()) {
@@ -3907,9 +3937,24 @@
   for (unsigned i = 0; i < Initializers.size(); i++) {
 CXXCtorInitializer 

Re: [PATCH] D19312: Warn about UB at member function calls from base class ctor initializers.

2016-04-20 Thread Filipe Cabecinhas via cfe-commits
filcab added a comment.

I meant changing the diff, but if you prefer to have a smaller comment, I'm ok 
with the different "paths" in the standards being mentioned only in the commit 
message.



Comment at: lib/Sema/SemaDeclCXX.cpp:3941
@@ +3940,3 @@
+  // 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

For someone reading the source code, it's probably best to mention the 
different "paths" in the standards here too.
For my usual source browsing, as long as it's in the comment *or* the commit 
message, I'll eventually see it. But it might throw some people off when they 
look at C++11, and there's no p16 in that place :-)


http://reviews.llvm.org/D19312



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D19312: Warn about UB at member function calls from base class ctor initializers.

2016-04-20 Thread Filipe Cabecinhas via cfe-commits
filcab added a subscriber: filcab.
filcab added a comment.

You might want to mention that it's 12.6.2p16 in C++14/17 but p13 in C++11.
I wonder if we should have the example in the standard, verbatim. (Plus the 
added tests you made)


http://reviews.llvm.org/D19312



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D19312: Warn about UB at member function calls from base class ctor initializers.

2016-04-20 Thread Raphael Isemann via cfe-commits
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 {
+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 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()] = 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">,