https://github.com/spaits updated 
https://github.com/llvm/llvm-project/pull/201379

From cd148bf201459dbe9ac18b8cf4a473147a67ab1e Mon Sep 17 00:00:00 2001
From: Gabor Spaits <[email protected]>
Date: Thu, 4 Jun 2026 21:50:26 +0200
Subject: [PATCH 1/7] [Sema]Report error for non-base types in constructor
 initializers before causing issue in initializer order

---
 clang/lib/Sema/SemaDeclCXX.cpp | 49 +++++++++++++++++-----------------
 1 file changed, 25 insertions(+), 24 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 418ff01f3d98a..215bd3a7d3327 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -17,6 +17,7 @@
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/ComparisonCategories.h"
+#include "clang/AST/DeclBase.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/DynamicRecursiveASTVisitor.h"
@@ -4819,33 +4820,33 @@ Sema::BuildBaseInitializer(QualType BaseType, 
TypeSourceInfo *BaseTInfo,
       return true;
   }
 
+  if (!Dependent && declaresSameEntity(ClassDecl, 
BaseType->getAsCXXRecordDecl()))
+    return BuildDelegatingInitializer(BaseTInfo, Init, ClassDecl);
+
   // Check for direct and virtual base classes.
   const CXXBaseSpecifier *DirectBaseSpec = nullptr;
   const CXXBaseSpecifier *VirtualBaseSpec = nullptr;
-  if (!Dependent) {
-    if (declaresSameEntity(ClassDecl, BaseType->getAsCXXRecordDecl()))
-      return BuildDelegatingInitializer(BaseTInfo, Init, ClassDecl);
-
-    FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec,
-                        VirtualBaseSpec);
-
-    // C++ [base.class.init]p2:
-    // Unless the mem-initializer-id names a nonstatic data member of the
-    // constructor's class or a direct or virtual base of that class, the
-    // mem-initializer is ill-formed.
-    if (!DirectBaseSpec && !VirtualBaseSpec) {
-      // If the class has any dependent bases, then it's possible that
-      // one of those types will resolve to the same type as
-      // BaseType. Therefore, just treat this as a dependent base
-      // class initialization.  FIXME: Should we try to check the
-      // initialization anyway? It seems odd.
-      if (ClassDecl->hasAnyDependentBases())
-        Dependent = true;
-      else
-        return Diag(BaseLoc, diag::err_not_direct_base_or_virtual)
-               << BaseType << Context.getCanonicalTagType(ClassDecl)
-               << BaseTInfo->getTypeLoc().getSourceRange();
-    }
+
+  FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec,
+                      VirtualBaseSpec);
+
+  // C++ [base.class.init]p2:
+  // Unless the mem-initializer-id names a nonstatic data member of the
+  // constructor's class or a direct or virtual base of that class, the
+  // mem-initializer is ill-formed.
+  if (!DirectBaseSpec && !VirtualBaseSpec) {
+    // If the class has any dependent bases, then it's possible that
+    // one of those types will resolve to the same type as
+    // BaseType. Therefore, just treat this as a dependent base
+    // class initialization.  FIXME: Should we try to check the
+    // initialization anyway? It seems odd.
+    if (ClassDecl->hasAnyDependentBases())
+      Dependent = true;
+    // We may have a delegating initializer
+    else if (!declaresSameEntity(ClassDecl, BaseType->getAsCXXRecordDecl()))
+      return Diag(BaseLoc, diag::err_not_direct_base_or_virtual)
+             << BaseType << Context.getCanonicalTagType(ClassDecl)
+             << BaseTInfo->getTypeLoc().getSourceRange();
   }
 
   if (Dependent) {

From 60e1c1fdeadc699efc7d08edca5862f63f584bf3 Mon Sep 17 00:00:00 2001
From: Gabor Spaits <[email protected]>
Date: Thu, 4 Jun 2026 22:26:40 +0200
Subject: [PATCH 2/7] Fix and clean up testing

---
 .../cppcoreguidelines/pro-type-member-init.cpp |  2 +-
 clang/test/SemaCXX/constructor-initializer.cpp | 18 ++++++++++++++++++
 .../warn-reorder-ctor-initialization.cpp       | 10 ----------
 3 files changed, 19 insertions(+), 11 deletions(-)

diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init.cpp
index 55963eae2c1b5..e1724c3c1e338 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init.cpp
@@ -647,7 +647,7 @@ namespace gh192510 {
   };
 
   template<typename T>
-  class X: public Base {
+  class X: public Base, private C<T> {
     using INT = C<T>;
 
     X(INT i) : INT(i) {} // no crash
diff --git a/clang/test/SemaCXX/constructor-initializer.cpp 
b/clang/test/SemaCXX/constructor-initializer.cpp
index 96be8dda97735..ff6374d6eb6ef 100644
--- a/clang/test/SemaCXX/constructor-initializer.cpp
+++ b/clang/test/SemaCXX/constructor-initializer.cpp
@@ -323,3 +323,21 @@ A f2(const B &b) {
   return b; // expected-error {{no matching constructor for initialization of 
'B'}}
 }
 }
+
+namespace PR7179 {
+struct X
+{
+  struct Y
+  {
+    template <class T> Y(T x) : X(x) { } // expected-error {{type 'X' is not a 
direct or virtual base of 'PR7179::X::Y'}}
+  };
+};
+}
+
+namespace PR201379 {
+struct S1 {
+  template<typename T>
+  S1(T) : d(), T()  {} // expected-error {{type 'T' is not a direct or virtual 
base of 'PR201379::S1'}}
+  int d;
+};
+}
diff --git a/clang/test/SemaCXX/warn-reorder-ctor-initialization.cpp 
b/clang/test/SemaCXX/warn-reorder-ctor-initialization.cpp
index 0613338945978..b0153c6984b5b 100644
--- a/clang/test/SemaCXX/warn-reorder-ctor-initialization.cpp
+++ b/clang/test/SemaCXX/warn-reorder-ctor-initialization.cpp
@@ -120,16 +120,6 @@ namespace test3 {
   };
 }
 
-namespace PR7179 {
-  struct X
-  {
-    struct Y
-    {
-      template <class T> Y(T x) : X(x) { }
-    };
-  };
-}
-
 namespace test3 {
   struct foo {
     struct {

From 10ce0dacdf643412bf7a9a8871f74d6cf433a3d2 Mon Sep 17 00:00:00 2001
From: Gabor Spaits <[email protected]>
Date: Thu, 4 Jun 2026 22:30:46 +0200
Subject: [PATCH 3/7] Fix and clean up testing and some formatting too

---
 clang/lib/Sema/SemaDeclCXX.cpp | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 215bd3a7d3327..aeb4258e9603d 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -4820,7 +4820,8 @@ Sema::BuildBaseInitializer(QualType BaseType, 
TypeSourceInfo *BaseTInfo,
       return true;
   }
 
-  if (!Dependent && declaresSameEntity(ClassDecl, 
BaseType->getAsCXXRecordDecl()))
+  if (!Dependent &&
+      declaresSameEntity(ClassDecl, BaseType->getAsCXXRecordDecl()))
     return BuildDelegatingInitializer(BaseTInfo, Init, ClassDecl);
 
   // Check for direct and virtual base classes.
@@ -4835,14 +4836,15 @@ Sema::BuildBaseInitializer(QualType BaseType, 
TypeSourceInfo *BaseTInfo,
   // constructor's class or a direct or virtual base of that class, the
   // mem-initializer is ill-formed.
   if (!DirectBaseSpec && !VirtualBaseSpec) {
-    // If the class has any dependent bases, then it's possible that
-    // one of those types will resolve to the same type as
-    // BaseType. Therefore, just treat this as a dependent base
-    // class initialization.  FIXME: Should we try to check the
-    // initialization anyway? It seems odd.
+    // If the class has any dependent bases, then it's possible that one of
+    // those types will resolve to the same type as BaseType. Therefore, just
+    // treat this as a dependent base class initialization.
+    // FIXME: Should we try to check the initialization anyway? It seems odd.
     if (ClassDecl->hasAnyDependentBases())
       Dependent = true;
-    // We may have a delegating initializer
+    // We may have a delegating initializer here, since that is also a type,
+    // that isn't a direct or virtual base of the instantiated type. That will
+    // be handled later.
     else if (!declaresSameEntity(ClassDecl, BaseType->getAsCXXRecordDecl()))
       return Diag(BaseLoc, diag::err_not_direct_base_or_virtual)
              << BaseType << Context.getCanonicalTagType(ClassDecl)

From 32b76252ff31ee9a376e84a018c233717e537038 Mon Sep 17 00:00:00 2001
From: Gabor Spaits <[email protected]>
Date: Thu, 4 Jun 2026 22:35:19 +0200
Subject: [PATCH 4/7] Comment

---
 clang/lib/Sema/SemaDeclCXX.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index aeb4258e9603d..125f2ba82553a 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -4842,9 +4842,9 @@ Sema::BuildBaseInitializer(QualType BaseType, 
TypeSourceInfo *BaseTInfo,
     // FIXME: Should we try to check the initialization anyway? It seems odd.
     if (ClassDecl->hasAnyDependentBases())
       Dependent = true;
-    // We may have a delegating initializer here, since that is also a type,
-    // that isn't a direct or virtual base of the instantiated type. That will
-    // be handled later.
+    // We may have a delegating initializer here but in a dependent context.
+    // Since that is also a type, that isn't a direct or virtual base of the
+    // instantiated type. That will be handled later.
     else if (!declaresSameEntity(ClassDecl, BaseType->getAsCXXRecordDecl()))
       return Diag(BaseLoc, diag::err_not_direct_base_or_virtual)
              << BaseType << Context.getCanonicalTagType(ClassDecl)

From 393f244a70537d93051e82b4795e4e5c721a51e2 Mon Sep 17 00:00:00 2001
From: Gabor Spaits <[email protected]>
Date: Wed, 24 Jun 2026 11:26:12 +0200
Subject: [PATCH 5/7] Think of the case where there is a base class

---
 clang/lib/Sema/SemaDeclCXX.cpp | 68 +++++++++++++++++++++++-----------
 1 file changed, 46 insertions(+), 22 deletions(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 125f2ba82553a..3e62fe3d30631 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -4802,6 +4802,7 @@ Sema::BuildBaseInitializer(QualType BaseType, 
TypeSourceInfo *BaseTInfo,
   bool Dependent = CurContext->isDependentContext() &&
                    (BaseType->isDependentType() || Init->isTypeDependent());
 
+  llvm::errs() << "Dependent? " << Dependent << '\n';
   SourceRange InitRange = Init->getSourceRange();
   if (EllipsisLoc.isValid()) {
     // This is a pack expansion.
@@ -4828,28 +4829,51 @@ Sema::BuildBaseInitializer(QualType BaseType, 
TypeSourceInfo *BaseTInfo,
   const CXXBaseSpecifier *DirectBaseSpec = nullptr;
   const CXXBaseSpecifier *VirtualBaseSpec = nullptr;
 
-  FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec,
-                      VirtualBaseSpec);
-
-  // C++ [base.class.init]p2:
-  // Unless the mem-initializer-id names a nonstatic data member of the
-  // constructor's class or a direct or virtual base of that class, the
-  // mem-initializer is ill-formed.
-  if (!DirectBaseSpec && !VirtualBaseSpec) {
-    // If the class has any dependent bases, then it's possible that one of
-    // those types will resolve to the same type as BaseType. Therefore, just
-    // treat this as a dependent base class initialization.
-    // FIXME: Should we try to check the initialization anyway? It seems odd.
-    if (ClassDecl->hasAnyDependentBases())
-      Dependent = true;
-    // We may have a delegating initializer here but in a dependent context.
-    // Since that is also a type, that isn't a direct or virtual base of the
-    // instantiated type. That will be handled later.
-    else if (!declaresSameEntity(ClassDecl, BaseType->getAsCXXRecordDecl()))
-      return Diag(BaseLoc, diag::err_not_direct_base_or_virtual)
-             << BaseType << Context.getCanonicalTagType(ClassDecl)
-             << BaseTInfo->getTypeLoc().getSourceRange();
-  }
+    FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec,
+                        VirtualBaseSpec);
+
+    // C++ [base.class.init]p2:
+    // Unless the mem-initializer-id names a nonstatic data member of the
+    // constructor's class or a direct or virtual base of that class, the
+    // mem-initializer is ill-formed.
+    if (!DirectBaseSpec && !VirtualBaseSpec) {
+      // If the class has any dependent bases, then it's possible that one of
+      // those types will resolve to the same type as BaseType. Therefore, just
+      // treat this as a dependent base class initialization.
+      // FIXME: Should we try to check the initialization anyway? It seems odd.
+      if (ClassDecl->hasAnyDependentBases())
+        Dependent = true;
+      // We may have a delegating initializer here but in a dependent context.
+      // Since that is also a type, that isn't a direct or virtual base of the
+      // instantiated type. That will be handled later.
+      //
+      // Another scenario we may get here is when the initialization list 
contains
+      // a type template parameter. If the class has any bases classes, the 
program can be valid, but if not, then the program must be invalid.
+      // For example, the following case must be invalid, no matter how we 
choose the type of the template at initialization:
+      //
+      // struct S0 {
+      //   S0(int) {}
+      //   template <class T>
+      //   S0(T) : T(42), Member(42) {};
+      //   int Member{21};
+      // };
+      // 
+      // This code can be valid, if we choose `SomeBase` as our template 
argument:
+      //
+      // class SomeBase {};
+      //
+      // struct S0 : SomeBase {
+      //   S0(int) {}
+      //   template <class T>
+      //   S0(T) : Member(42), T(42) {};
+      //   int Member{21};
+      // };
+      else if (!declaresSameEntity(ClassDecl, BaseType->getAsCXXRecordDecl()) 
&&
+               ClassDecl->bases().empty())
+        return Diag(BaseLoc, diag::err_not_direct_base_or_virtual)
+               << BaseType << Context.getCanonicalTagType(ClassDecl)
+               << BaseTInfo->getTypeLoc().getSourceRange();
+    }
 
   if (Dependent) {
     DiscardCleanupsInEvaluationContext();

From f6d280c123045254d8fd7a95fe471c9cffc134de Mon Sep 17 00:00:00 2001
From: Gabor Spaits <[email protected]>
Date: Wed, 24 Jun 2026 11:31:26 +0200
Subject: [PATCH 6/7] Remove unnecessary include

---
 clang/lib/Sema/SemaDeclCXX.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 3e62fe3d30631..578ae9506db3c 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -17,7 +17,6 @@
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/ComparisonCategories.h"
-#include "clang/AST/DeclBase.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/DynamicRecursiveASTVisitor.h"

From 14b2e163bdc1be5d5c15babc5768a40d14915067 Mon Sep 17 00:00:00 2001
From: Gabor Spaits <[email protected]>
Date: Wed, 24 Jun 2026 11:36:29 +0200
Subject: [PATCH 7/7] Yeah the debug print shouldnt really stay in the pr

---
 clang/lib/Sema/SemaDeclCXX.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 578ae9506db3c..26d247013c682 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -4801,7 +4801,6 @@ Sema::BuildBaseInitializer(QualType BaseType, 
TypeSourceInfo *BaseTInfo,
   bool Dependent = CurContext->isDependentContext() &&
                    (BaseType->isDependentType() || Init->isTypeDependent());
 
-  llvm::errs() << "Dependent? " << Dependent << '\n';
   SourceRange InitRange = Init->getSourceRange();
   if (EllipsisLoc.isValid()) {
     // This is a pack expansion.

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to