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

Reply via email to