Re: [PATCH] D19312: Warn about UB at member function calls from base class ctor initializers.
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.
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.
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::SmallVectorInitFieldIndex; +// 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.
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.
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.
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.
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.
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.
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">,