Author: Aaron Puchert Date: 2026-08-24T14:34:11+02:00 New Revision: 74609eda08d8533303fcf0fd028b9c4375d58e6b
URL: https://github.com/llvm/llvm-project/commit/74609eda08d8533303fcf0fd028b9c4375d58e6b DIFF: https://github.com/llvm/llvm-project/commit/74609eda08d8533303fcf0fd028b9c4375d58e6b.diff LOG: [Clang][Sema] Don't warn on accessing virtual base from abstract class (#217715) Virtual bases are initialized by the most derived class, and they come before non-virtual base class initializers. So an abstract class can assume that virtual bases are already initialized by the time their constructor runs. It seems that the warning generally doesn't take indirect bases into account, otherwise this would become a bit more complicated. Fixes #204858. Added: Modified: clang/lib/Sema/SemaDeclCXX.cpp clang/test/SemaCXX/uninitialized.cpp Removed: ################################################################################ diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 277e990f248c0..45e0cafeed040 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -4161,8 +4161,13 @@ namespace { } llvm::SmallPtrSet<QualType, 4> UninitializedBaseClasses; - for (const auto &I : RD->bases()) + for (const auto &I : RD->bases()) { + // Virtual bases are initialized from the most derived class, so an + // abstract base class constructor can assume it to be initialized. + if (I.isVirtual() && RD->isAbstract()) + continue; UninitializedBaseClasses.insert(I.getType().getCanonicalType()); + } if (UninitializedFields.empty() && UninitializedBaseClasses.empty()) return; diff --git a/clang/test/SemaCXX/uninitialized.cpp b/clang/test/SemaCXX/uninitialized.cpp index cc368c22e0776..9ecea1ac4cc3b 100644 --- a/clang/test/SemaCXX/uninitialized.cpp +++ b/clang/test/SemaCXX/uninitialized.cpp @@ -1411,6 +1411,8 @@ struct B : public A { B(int (*)[4]) : A(foo()) {} // expected-warning@-1 {{base_class_access::A' is uninitialized when used here to access 'base_class_access::A::foo'}} + + virtual void f() = 0; }; struct C { @@ -1428,6 +1430,22 @@ struct D : public C, public A { // expected-warning@-1 {{base_class_access::A' is uninitialized when used here to access 'base_class_access::A::foo'}} }; +struct E : public virtual A { + E(int (*)[3]) : A(i) {} + // expected-warning@-1 {{base class 'base_class_access::A' is uninitialized when used here to access 'base_class_access::A::i'}} + + E(int (*)[4]) : A(foo()) {} + // expected-warning@-1 {{base_class_access::A' is uninitialized when used here to access 'base_class_access::A::foo'}} +}; + +// Accessing virtual base class members from an abstract class is fine. +struct F : public virtual A, public C { + F(int (*)[3]) : C(i) {} + F(int (*)[4]) : C(foo()) {} + + virtual void f() = 0; +}; + } namespace value { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
