Test suite passes now, didn't realize it wasn't before.
http://reviews.llvm.org/D6561
Files:
include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDeclCXX.cpp
test/SemaCXX/member-call-before-bases-init.cpp
test/SemaCXX/uninitialized.cpp
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -1509,6 +1509,9 @@
def note_uninit_in_this_constructor : Note<
"during field initialization in %select{this|the implicit default}0 "
"constructor">;
+def warn_member_call_before_bases_init : Warning<
+ "member function %0 called before all base classes were initialized">,
+ InGroup<Uninitialized>;
def warn_static_self_reference_in_init : Warning<
"static variable %0 is suspiciously used within its own initialization">,
InGroup<UninitializedStaticSelfInit>;
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -2638,6 +2638,44 @@
}
} // namespace
+namespace {
+class DiagnoseMemberCallVisitor
+ : public RecursiveASTVisitor<DiagnoseMemberCallVisitor> {
+ Sema &S;
+
+public:
+ DiagnoseMemberCallVisitor(Sema &SemaRef) : S(SemaRef) {}
+
+ bool VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
+ const Expr *IA = E->getImplicitObjectArgument();
+ if (IA->isImplicitCXXThis() || isa<CXXThisExpr>(IA)) {
+ S.Diag(E->getExprLoc(), diag::warn_member_call_before_bases_init)
+ << E->getDirectCallee();
+ }
+ return true;
+ }
+};
+
+// Diagnoses method calls before all base classes are initialized in a
+// mem-initializer-list which is undefined behaviour.
+// Source: C++03 12.6.2p8; C++11 12.6.2p13.
+static void
+DiagnoseUndefinedMemberFunctionCalls(Sema &SemaRef,
+ const CXXConstructorDecl *Constructor) {
+ if (SemaRef.getDiagnostics().isIgnored(
+ diag::warn_member_call_before_bases_init, Constructor->getLocation()))
+ return;
+
+ DiagnoseMemberCallVisitor Visitor(SemaRef);
+ for (const auto *I : Constructor->inits()) {
+ if (!I->isBaseInitializer())
+ continue;
+ Expr *E = I->getInit();
+ Visitor.TraverseStmt(E);
+ }
+}
+} // namespace
+
/// \brief Enter a new C++ default initializer scope. After calling this, the
/// caller must call \ref ActOnFinishCXXInClassMemberInitializer, even if
/// parsing or instantiating the initializer failed.
@@ -4242,6 +4280,7 @@
SetCtorInitializers(Constructor, AnyErrors, MemInits);
DiagnoseUninitializedFields(*this, Constructor);
+ DiagnoseUndefinedMemberFunctionCalls(*this, Constructor);
}
void
Index: test/SemaCXX/member-call-before-bases-init.cpp
===================================================================
--- test/SemaCXX/member-call-before-bases-init.cpp
+++ test/SemaCXX/member-call-before-bases-init.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -fsyntax-only -Wuninitialized -verify %s
+
+class A {
+public:
+ A(int);
+};
+
+int g(int);
+
+class B : public A {
+ int j;
+
+public:
+ int f();
+ B() : A(g(f())), // expected-warning{{member function 'f' called before all base classes were initialized}}
+ j(f()) {} // no-warning
+
+ B(int) : A(this->f()), // expected-warning{{member function 'f' called before all base classes were initialized}}
+ j(0) {}
+};
+
+class C {
+public:
+ C(int);
+};
+
+class D : public B, C {
+ int i;
+
+public:
+ D() : C(f()), // expected-warning{{member function 'f' called before all base classes were initialized}}
+ i(f()) {} // no-warning
+};
Index: test/SemaCXX/uninitialized.cpp
===================================================================
--- test/SemaCXX/uninitialized.cpp
+++ test/SemaCXX/uninitialized.cpp
@@ -1323,6 +1323,7 @@
B(int (*)[4]) : A(foo()) {}
// expected-warning@-1 {{base_class_access::A' is uninitialized when used here to access 'base_class_access::A::foo'}}
+ // expected-warning@-2 {{member function 'foo' called before all base classes were initialized}}
};
struct C {
@@ -1338,6 +1339,7 @@
D(int (*)[4]) : C(foo()) {}
// expected-warning@-1 {{base_class_access::A' is uninitialized when used here to access 'base_class_access::A::foo'}}
+ // expected-warning@-2 {{member function 'foo' called before all base classes were initialized}}
};
}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits